Git Product home page Git Product logo

lectrote's Introduction

Lectrote

Lectrote logo: purple compass

The IF interpreter in an Electron shell

Lectrote packages up IF interpreters with the Chromium browser as a Mac/Win/Linux app.

When launched, it prompts you to select a game file to play. You can play several games at the same time in separate windows. Your position is always autosaved; when you launch a game, your last play session will automatically be resumed.

Lectrote currently supports:

  • Glulx games (.ulx or .gblorb), as produced by Inform 7.
  • Z-code games (.z3/.z4/.z5/.z8 or .zblorb), as produced by Inform 7 or earlier versions of Inform.
  • Hugo games (.hex).
  • TADS2 and TADS3 games (.gam, .t3).
  • Adrift 4 games (.taf).
  • Ink compiled game files (.json), as produced by the Ink scripting language.

You can also use this package to construct a "bound game" -- an app which plays a single built-in game. This is a package containing Chromium, the interpreter, your game file, and perhaps some additional configuration. You can distribute this as a standalone game application; it's bulky but it lets people play your game.

Linux note: Depending on your Linux configuration and how you install this package, you may have to add the --no-sandbox option when launching Lectrote.

Glulx (Inform 7) support

Because this relies on the Quixe interpreter, sound is not supported. It's also not as fast as a native interpreter.

Z-code support

Lectrote uses the ZVM interpreter for Z-machine support. (V3/4/5 and V8 only.)

Hugo support

The Hugo engine does not currently support autosave.

TADS support

The TADS 2/3 engine does not currently support autosave.

Adrift 4 support

The Adrift 4 engine does not currently support autosave.

Ink support

This relies on the inkjs interpreter. It is a deliberately non-fancy presentation -- no attempt to slow-print the output or hide the choice list.

License information

  • Lectrote is copyright (c) 2016-2023, Andrew Plotkin (MIT license)
  • Electron is copyright (c) 2013-2023 GitHub Inc. (MIT license)
  • Quixe is copyright (c) 2010-2023, Andrew Plotkin (MIT license)
  • inkjs is copyright (c) 2017-2023 Yannick Lohse (MIT license)
  • ifvms.js is copyright (c) 2016-2023 Dannii Willis and other contributors (MIT license)
  • emglken is copyright (c) 2012-2023, Andrew Plotkin, Dannii Willis (MIT license)
  • Git (in emglken) is copyright (c) 2003 Iain Merrick (MIT license)
  • Glulxe (in emglken) is copyright (c) 1999-2023, Andrew Plotkin (MIT license)
  • Hugo (in emglken) is copyright (c) 2011 by Kent Tessman (BSD license)
  • TADS (in emglken) is copyright (c) 1991-2012 by Michael J. Roberts (dual-licensed GPL/TADS license)
  • Scare (in emglken) is copyright (c) 2003-2008, Simon Baldwin and Mark J. Tilford (GPL)
  • RemGlk (in emglken) is copyright (c) 2012-2023, Andrew Plotkin (MIT license)

For developers

If you've just downloaded the source code for this puppy, it's easy to make a runnable version.

First, you need to have the Node development tools installed. Everything relies on the npm command-line tool. See Installing Node.js via package manager.

To fetch all the necessary Node packages and place them in a node_modules directory:

npm install

This command also fetches the Quixe submodule (which will live in the quixe directory). You must have git installed for this to work.

Now just type

npm start

...to launch the app.

When run this way, the app will show up named as "Electron", not "Lectrote".

Packaging Lectrote

The makedist.py script builds the zip files which you see on the release page. (Yes, it is silly to use a Python packaging script in a Node.js package. Maybe I'll rewrite it into Javascript. Later.)

python3 makedist.py

This creates build directories and then zip files in a dist directory. Add -b to only generate the build dirs; -z to transform existing build dirs into zip files.

You can add arguments to narrow down the platforms you are building, e.g.:

python3 makedist.py darwin
python3 makedist.py win32
python3 makedist.py linux
python3 makedist.py win32-x64

Note that "darwin" includes "darwin-x64", "darwin-arm64", and "darwin-universal" (both packaged together).

If you want to code-sign the Mac version, use the --macsign argument:

python3 makedist.py darwin --macsign 'Developer ID Application: ...'

You must be a registered Apple developer to do this. The argument must be the name of the "Developer Id Application" certificate in your keychain. Run the Keychain Access app to see this. If you don't have one, the easiest way to set it up is to run Xcode, open the Preferences, select Accounts, and hit Manage Certificates.

Packaging a bound game

You will need to create a separate directory for your game's files. Copy package.json to the directory, adding or modifying these lines:

  • name: A node package name. This is not used anywhere, so it doesn't really matter.
  • productName: The display name for the app.
  • version: Version number of your game.
  • author: You, the game's author.
  • description: One-line description of your game.
  • lectrotePackagedGame: Pathname to the game file.
  • lectroteSoleInterpreter: Set to "ifvms", "inkjs", "emglken" to include just one of Lectrote's interpreter engines. (Optional, but it saves a little bit of space.) (Note that Git, Glulxe, Hugo, and TADS are all handled by the emglken package. There's currently no way to include just one of them.)
  • lectroteExtraFiles: An array of extra files to include. These are assumed to be in the game directory, so you do not have to include the directory prefix. (This list must include the game file -- yes, it's redundant with lectrotePackagedGame.)
  • lectroteMacAppID: If you plan to build a MacOS app, a reverse-DNS ID string to uniquely identify it.
  • lectroteCopyright: Copyright string (applied to Windows binaries).

(Do not change lectroteVersion; that should always show the Lectrote release that you built your bound app from.)

To create a Mac DMG archive, you will also need a resources/pack-dmg-spec.json file. See samplegame/resources/pack-dmg-spec.json. You should update the "title", the "dist/Adventure-$PLATFORM$" paths under "contents", and (if you want) the "background" image which is used for the folder window.

You may also copy any of Lectrote's content files to your game directory and customize them. You will probably want to customize about.html, for example.

The samplegame directory in the Lectrote source demonstrates the layout. It will be simplest to clone that and alter it.

Once your files are ready, do:

python3 makedist.py --game GAMEDIR

This will build and package apps for all platforms. (You can test this out of the box by using samplegame for the GAMEDIR.) As noted above, you can cut down the stages or targets with the -b, -z options or by naming platforms.

You cannot launch a bound game by typing npm start. You have to package it, at least to the -b stage, and run it from the dist directory.

Customizing your bound app

As noted, you can copy play.html, el-glkote.css, or other Lectrote files into your gamedir and customize them. When packaging with the --game option, files found in the gamedir will replace normal Lectrote files.

If you add new files (not replacing Lectrote files), be sure to list them in the lectroteExtraFiles array.

You can extend the functionality of the app -- for example, adding or removing menu items. Add a Javascript file to your gamedir, and name it in your package.json file:

"lectroteMainExtension": "GAMEDIR/FILE.js",

(And add it to lectroteExtraFiles as well.)

This file can define new functionality by exporting any of the following Javascript functions. For example, you could say:

exports.launch = function() { ... }
  • exports.launch(): Called when the app starts up.
  • exports.app_ready(): Called when the app is ready to open windows. At this point the game window has already been opened.
  • exports.construct_menu_template(template, special): Called to customize the app menu template. The template argument is a Javascript data structure as described in the Electron Menu docs. special is null for the game window, or one of the strings "about", "prefs", "card" for one of Lectrote's special windows. Modify template and return it.
  • exports.set_zoom_factor(val): Called when the app's zoom level changes. The argument is suitable for Electron's setZoomFactor() method.
  • exports.set_darklight_mode(val): Called when the OS native theme changes. The argument is false for light theme, true for dark theme.
  • exports.export_game_path(): The bound app normally has an "Export Portable Game File..." menu option, which lets the user extract your game file for use in other interpreters. You can implement this function and return null to suppress this menu option. You can also return the pathname of a different game file, which is not actually a useful thing to do.
  • exports.cover_image_info: An object { url:URL, width:W, height:H } which provides cover art. This is only needed if your game is not a blorb file. (If it is not provided, Lectrote attempts to load the blorb cover art as usual.)
  • exports.about_window_size: An object { width:W, height:H } which customizes the size of the about.html window. (Defaults to { width:600, height:450 }.)

The main Lectrote module exports several functions you can use in your extension code. I have not yet documented them; see the main.js file.

Style customizations for dark/light mode

As of release 1.3.6 (August 2020), Lectrote supports OS dark theme. You should do the same for any windows you have added or customized.

Look at about.html to see how this works. The evhan_darklight() function alters the document style; the onready() function now sets up a callback for this function. The <body> tag now has <body id="body"> to support this, and several .DarkMode stanzas have been added to the CSS. You should copy these changes in your own about.html.

When opening a window, use a backgroundColor line to set the loading color, minimizing flash:

backgroundColor: (electron.nativeTheme.shouldUseDarkColors ? '#000' : '#FFF'),

Then, in the dom-ready event, send a message to convey the OS theme:

win.webContents.send('set-darklight-mode', electron.nativeTheme.shouldUseDarkColors);

Also add a set_darklight_mode() routine to your extension code (see above). This routine should send the same message to all open windows.

In the window, set up a handler for this message and adjust your body styles appropriately:

require('electron').ipcRenderer.on('set-darklight-mode', function(ev, arg) {
	// arg is false for light mode, true for dark mode.
});

See about.html and if-card.html for examples of dark/light style handling.

Be sure to test that your windows open with the appropriate theme (matching the OS theme), and also that they change dynamically when the OS theme changes.

lectrote's People

Contributors

0branch avatar curiousdannii avatar erkyrath avatar nebocamin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lectrote's Issues

Think about display preferences

We now have too many prefs in the View menu. It's getting to be time for a Preferences dialog.

When a pref changes, I think it changes every open window. The current compromise of changing one at a time, but only saving a single preference, is silly.

Scroll bar position

Maybe we can fix the silly scroll-bar offset by (a) giving the gameport the entire window; (b) instead of true margins, apply left or right padding to windows that reach the left or right edge of the gameport. This would require GlkOte to tack a CSS class onto left-edge or right-edge windows.

It's hacky but I think it would work sensibly. Have to test a two-column game, of course.

Let the user add a customized stylesheet

Hardcode display customization. This is the Gargoyle solution, which we all agree is terrible, but I think it's good to allow it.

Maybe drop a css file into ~/Library.

Undo/Redo menu options are confusing

Technically they work -- you can undo and redo changes in your typed input line. (Until you hit enter.) But this is not what people expect Undo in an IF app to accomplish. Might be best to disable them, if they get enabled in appropriate contexts. Otherwise, omit.

Use a stable branch of quixe

I bang around on quixe:master a lot. If people are going to be installing lectrote, it should pick a point in quixe that is known to be good. (Both the submodule ref and the git-clone script in the package.)

Probably this means making a quixe:stable branch and syncing it to master at release time. Maybe more often.

Inconsistent fonts on Mac/Win/Linux

The current CSS says

    /* body text */
     font-family: Palatino, Georgia, serif;
    /* fixed-width text */
     font-family: monaco, andale mono, lucidatypewriter, courier, courier new, monospace;

But of course this is entirely dependent on what you have installed. Switch over to app-packaged web fonts.

Make sure cli.sh works locally

Spun off from #20

Comment from dannii:

You should be able to use the npm_config_binroot config var in cli.sh - if you're asking for npm root -g then it won't work when it's running locally, won't it?

Sign Mac app

(We will need an unsigned version lying around for bound games.)

Zoom preference can get stuck at "very tiny" or "very large"

If you use the zoom slider in the preferences dialog, and then use the cmd-+ cmd-- shortcuts, the zoom factor can jump to one end of the scale and get stuck.

This is because I was mixing string values (from the DOM select.val()) with numeric values. The fix is to ensure the value is always a number.

OS X also has Electron icon

On the release notes, you mention Windows versions don't get a custom icon -- I get the same on my OS X install (10.11.2).

screen shot 2016-01-26 at 7 24 11 pm

Auto-save

This is really a Quixe feature. Once it exists, we can autosave the game to ~/Library after every move, and then we can launch the game in the last-known state when it's opened.

Quitting from prompt should do something

Steps to Reproduce:

  1. Run Lectrote, start a game.
  2. Type quit
  3. When the game asks if you want to quit. Type y and hit Enter

Observed behaviour: The flashing cursor disappears
Expected behaviour: I'm not sure, but something should probably happen. The window should close? Or maybe it should return to the Lectrote start page? Or maybe it should just display a message along the lines of: "Game quit. Click on File->Open to start another."

Prevent a game from running in two windows at once

It will confuse autosave. Will confuse players too.

We distinguish games by checksum, not filename. So even if the player copies a game under a different name, they can't play it twice. This will annoy somebody.

Font preference

I should probably ship some open-source fonts rather than trying to guess what's available.

"Invalid Glulx file" when launched via "npm start"

On Win/Linux only.

For Win/Linux we assume that argv[1...] are launch arguments (dragged-in files). This is true for the prepackaged app, but for npm start, the args are [electron, main.js].

I guess I need a way to distinguish the two launch environments. Or I could treat "main.js" as a magic string, but that's terrible.

Scroll bar visibility

Make the track more visible. Possibly only on hover?

The fact that the scroll bar is not against the window margin is a result of how I've laid out the HTML divs. It's not easily fixable (I'm sorry to say).

Open Recent menu is not updated dynamically

The "Open Recent" submenu is populated when you launch the app, but does not change thereafter. You have to quit and restart to see changes.

(I'm talking about the submenu of "File". The recent-items list in the Dock pop-up menu works correctly, thanks to app.addRecentDocument.)

This is not currently fixable. It's not possible to update an application submenu on the fly: electron/electron#527

It's supposed be possible to add to a submenu (using Menu.insert), but when I tried, it didn't work. It's also supposed to be possible to replace the entire menu tree (with Menu.setApplicationMenu) -- but that seems like overkill, and there are some bugs filed about it. So I'm just leaving this alone until Electron improves its menu handling.

Turn on detect_external_links=search

Perhaps this should be a user preference, though.

Make sure links are thrown to OS browser! (However I did that in the postcard window.)

Distinct style for external URLs. I'm thinking dotted underlines.

First time Mac app is launched, you get an error dialog

"The game file could not be read: ENOENT: -psn_0_12331970"

When the app is launched and MacOS shows the "This app is downloaded from the internet" dialog, that -psn_... argument shows up in sys.argv. Why? I don't know. I'm gonna have to special-case that too.

Internationalization

This would cover the menus, assorted messages and strings in main.js, and the About and IF-Postcard windows.

There's an app.getLocale call in Electron.

I18N would not extend down into Quixe or GlkOte themselves, as they have little to say.

"Restart" menu item

Once autosave is up, we'll need a way to say "Restart and ignore the autosave". (A bug in the autosave/autorestore code might lead to the game crashing every time you launch it. That's bad.)

This might as well be a general "Restart Game" menu item. (With a confirmation dialog.)

Rethink splash screen layout

Menus on the about window (and the card window) continue to confuse Windows users. It's worth rethinking this even if I don't have a great answer.

Definitely add a popup "recent..." menu button on the about window.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.