Skip to content

Commit

Permalink
feat: WIP narrat editor (#167)
Browse files Browse the repository at this point in the history
* feat: basic setup for editor

* feat: narrat editor working

* fix: ts error

* fix: tests and keyboard focus
  • Loading branch information
liana-p committed Oct 15, 2023
1 parent a02aa54 commit aa6b164
Show file tree
Hide file tree
Showing 60 changed files with 1,032 additions and 68 deletions.
2 changes: 1 addition & 1 deletion demo-template/src/css/main.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* See https://docs.narrat.dev/guides/theming-the-game-and-ui for info on how to customise your game with CSS. */

#app {
#narrat-app {
/* Customise CSS variables here. They will override the existing narrat ones. You can also add your own variables */
--bg-color: #131720;
--text-color: #d9e1f2;
Expand Down
3 changes: 2 additions & 1 deletion docs/guides/installing-narrat-in-a-web-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ For narrat to run, it needs two pieces of data:
- The `config` file which contains the path of your script files and other info
- The `characters` file which contains the list of characters in the game

Copy the content of one of the [example games](https://github.com/liana-p/narrat-engine/tree/main/packages/narrat/examples/) and the content of the assets folder somewhere in your app that can be served statically, and have an `#app` div in your page's html including your javascript \(you can copy `public/index.html`\) .
Copy the content of one of the [example games](https://github.com/liana-p/narrat-engine/tree/main/packages/narrat/examples/) and the content of the assets folder somewhere in your app that can be served statically, and have a div in your page's html including your javascript \(you can copy `public/index.html`\) .

Then in your javascript code to launch narrat, use:

Expand All @@ -28,5 +28,6 @@ startApp({
configPath: 'data/config.yaml',
scripts,
debug,
container: myContainer, // The container is the div where the game will be rendered
});
```
2 changes: 1 addition & 1 deletion docs/guides/using-custom-fonts.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ In your `src/css/main.css` file, add the following `@font-face` directive for ea
If you want to override the default font (used pretty much everywhere), you can change the `--font-family` css variable which narrat uses.

```css
#app {
#narrat-app {
/* Customise CSS variables here. They will override the existing narrat ones. You can also add your own variables */
--bg-color: #131720;
--text-color: #d9e1f2;
Expand Down
2 changes: 1 addition & 1 deletion packages/create-narrat/template/src/css/main.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* See https://docs.narrat.dev/guides/theming-the-game-and-ui for info on how to customise your game with CSS. */

#app {
#narrat-app {
/* Customise CSS variables here. They will override the existing narrat ones. You can also add your own variables */
--bg-color: #131720;
--text-color: #d9e1f2;
Expand Down
24 changes: 24 additions & 0 deletions packages/narrat-editor/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
3 changes: 3 additions & 0 deletions packages/narrat-editor/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
}
18 changes: 18 additions & 0 deletions packages/narrat-editor/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Vue 3 + TypeScript + Vite

This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.

## Recommended IDE Setup

- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).

## Type Support For `.vue` Imports in TS

TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.

If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:

1. Disable the built-in TypeScript Extension
1. Run `Extensions: Show Built-in Extensions` from VSCode's command palette
2. Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
13 changes: 13 additions & 0 deletions packages/narrat-editor/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Narrat Editor</title>
</head>
<body>
<div id="app" class="w-full"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
48 changes: 48 additions & 0 deletions packages/narrat-editor/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"name": "narrat-editor",
"description": "Interactive editor for narrat games",
"private": true,
"version": "0.0.0",
"type": "module",
"keywords": [
"game"
],
"author": "Liana Pigeot",
"license": "MIT",
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"preview": "vite preview"
},
"engines": {
"node": ">=18"
},
"repository": {
"type": "git",
"url": "[email protected]:liana-p/narrat-engine.git",
"directory": "packages/narrat-editor"
},
"homepage": "https://narrat.dev",
"files": [
"dist/"
],
"dependencies": {
"clone-deep": "^4.0.1",
"monaco-editor": "0.44.0",
"monaco-yaml": "^5.1.0",
"narrat": "workspace:*",
"pinia": "^2.1.7",
"vue": "^3.3.4"
},
"devDependencies": {
"@types/clone-deep": "^4.0.1",
"@vitejs/plugin-vue": "^4.2.3",
"typescript": "^5.0.2",
"vite": "^4.4.5",
"vite-plugin-monaco-editor": "^1.1.0",
"vite-plugin-narrat": "workspace:*",
"vite-plugin-windicss": "^1.9.0",
"vue-tsc": "^1.8.5",
"windicss": "^3.5.6"
}
}
7 changes: 7 additions & 0 deletions packages/narrat-editor/public/data/audio.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
files: {}
options:
volume: 0.5
musicFadeInTime: 0.5
musicFadeInDelay: 0.5
musicFadeOutTime: 0.5
audioTriggers: {}
1 change: 1 addition & 0 deletions packages/narrat-editor/public/data/buttons.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
buttons: {}
11 changes: 11 additions & 0 deletions packages/narrat-editor/public/data/characters.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
config:
imagesPath: img/characters/
characters:
game:
name: ''
color: white
player:
style:
color: orange
name: You
41 changes: 41 additions & 0 deletions packages/narrat-editor/public/data/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
gameTitle: Narrat Game Example
saveFileName: Narrat Empty
images: {}
dialogPanel:
textSpeed: 30
animateText: true
timeBetweenLines: 100
overlayMode: true
rightOffset: 100
bottomOffset: 50
width: 475
height: 680
layout:
backgrounds:
width: 1280
height: 720
dialogBottomPadding: 70
mobileDialogHeightPercentage: 60
verticalLayoutThreshold: 600
portraits:
width: 100
height: 100
screens: data/screens.yaml
buttons: data/buttons.yaml
skills: data/skills.yaml
skillChecks: data/skillchecks.yaml
characters: data/characters.yaml
audio: data/audio.yaml
notifications:
timeOnScreen: 2.5
hudStats: {}
items: data/items.yaml
interactionTags:
default:
onlyInteractOutsideOfScripts: true
quests: data/quests.yaml
menuButtons: {}
saves:
mode: manual
slots: 10
1 change: 1 addition & 0 deletions packages/narrat-editor/public/data/items.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
items: {}
4 changes: 4 additions & 0 deletions packages/narrat-editor/public/data/quests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
categories:
- id: default
title: Default quest category
quests: {}
5 changes: 5 additions & 0 deletions packages/narrat-editor/public/data/screens.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
screens:
default:
background: img/backgrounds/curtain.webp
game:
background: img/backgrounds/map.webp
20 changes: 20 additions & 0 deletions packages/narrat-editor/public/data/skillchecks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
options:
diceRange: [1, 6] # Dice rolls will be between those 2 numbers, inclusive
diceCount: 2 # How many dice are rolled by default on skill checks
extraPointsPerLevel: 1 # How many extra points to your rolls are given per level in the skill
extraDicePerLevel: 0 # How many extra dice the player gets per level in the skill (Default 0)
successOnRollsBelowThreshold: false # Inverts the skillcheck behaviour so that success is when the roll is *below* the difficulty threshold
showDifficultyText: true # Whether to show the difficulty text on the skill check
showDifficultyNumber: true # Whether to show the difficulty number on the skill check
showDifficultyWithoutModifiers: false # Whether to show the original difficulty without modifiers applied on the skill check
totalRollIsHighest: false # Uses only the highest roll to do the final skill check comparison, instead of adding up all rolls
totalRollIsLowest: false # Uses only the lowest roll to do the final skill check comparison, instead of adding up all rolls
difficultyText: # Text to show for each band of difficulty level
- [2, 'Very Easy']
- [4, 'Easy']
- [6, 'Medium']
- [8, 'Hard']
- [10, 'Very Hard']
- [11, 'Extremely Hard']
- [12, 'Near Impossible']
skillChecks: {}
1 change: 1 addition & 0 deletions packages/narrat-editor/public/data/skills.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
skills: {}
Binary file not shown.
Binary file not shown.
1 change: 1 addition & 0 deletions packages/narrat-editor/public/vite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions packages/narrat-editor/src/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<script setup lang="ts">
import MonacoEditor from './components/MonacoEditor.vue';
import NarratPreview from './components/NarratPreview.vue';
</script>
<template>
<div class="w-full bg-neutral-900">
<div class="container mx-auto p-5">
<h1 class="title text-center">Narrat Editor!</h1>
<p class="text">
Edit your narrat scripts on the left, the game will live reload on the
right.
</p>
</div>
<div class="gap-4 w-full editor-layout flex justify-between h-screen">
<MonacoEditor class="flex-grow h-screen w-1/2" />
<NarratPreview class="game-preview flex-grow h-screen w-1/2" />
</div>
</div>
</template>

<style scoped></style>
1 change: 1 addition & 0 deletions packages/narrat-editor/src/assets/vue.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
59 changes: 59 additions & 0 deletions packages/narrat-editor/src/components/MonacoEditor.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<template>
<div>
<div ref="editorContainer" class="h-full"></div>
</div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted, shallowRef } from 'vue';
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
import { useGameStore } from '@/stores/game-store';
import { debounce } from 'narrat';
export type MonacoEditor = ReturnType<typeof monaco.editor.create>;
const editor = shallowRef<MonacoEditor | null>(null);
const editorContainer = ref<HTMLDivElement | null>(null);
const gameStore = useGameStore();
onMounted(() => {
console.log('mounted');
if (editorContainer.value) {
if (!editor.value) {
const scriptToEdit = gameStore.activeScript;
if (scriptToEdit) {
editor.value = monaco.editor.create(editorContainer.value!, {
language: 'python',
value: scriptToEdit.code,
automaticLayout: true,
theme: 'vs-dark',
});
editor.value.onDidChangeModelContent(
debounce(() => {
editorContentChanged();
}, 1000),
);
} else {
console.error('scriptToEdit is null');
}
}
} else {
console.error('editorContainer is null');
}
});
function editorContentChanged() {
if (editor.value) {
gameStore.updateCurrentFileCode(editor.value.getValue());
} else {
console.error('editor is null');
}
}
onUnmounted(() => {
if (editor.value) {
editor.value.dispose();
}
});
</script>

<style scoped></style>
Loading

0 comments on commit aa6b164

Please sign in to comment.