Origami Projector (hereafter, Projector) is an editor and expression evaluation system for quickly iterating on code, data, and content.
Projector shortens the conventional cycle in which you edit a text file (e.g., a markdown file), save it, run some code to generate an affected artifact (a HTML file incorporating that content), view the artifact, then edit again.
Traditional cycle: Edit → Save → Run → View → (repeat)
Projector cycle: Edit → View → (repeat)
Projector is aimed at developers and designers, as well as people with a degree of technical comfort who do not think of themselves as coders. To that end, Projector is envisioned as a standalone application for performing tasks which are normally done with a terminal.
Projector is designed to coexist with other design and development tools such as code editors (e.g., Microsoft VS Code, NeoVim), text editing applications (Obsidian, iA Writer), and command-line shells (bash).
For the present time, Projector is only available on macOS for Apple Silicon. The projector is architected to allow for the possible addition of Windows and/or Linux versions in the future.
Every time you edit a file in Origami Projector, it automatically saves changes. Before using Projector, save your files in source control or elsewhere so that a bug doesn’t cause you to lose work!
Because the app is not distributed through the App Store, you must manually download it and approve its use.
- Open the Releases page and download the
.dmgfile attached to the latest release. - Open the
.dmgfile and drag the Origami Projector application into your Applications folder. - Open your Applications folder and double-click Origami projector.
- macOS will tell you that the application cannot be opened — but it will remember that you wanted to open it.
- Now open macOS System Settings, then Privacy & Security.
- Scroll down to Security. You should see a message saying that Origami Projector was blocked.
- Click Open Anyway.
The initial feature set is small and designed to be reasonably self-consistent. That said, even an extremely basic file-editing application carries high user expectations.
The focus at this early stage is confirming the idea’s viability and working out the proper shape of the tool. The current app experience is all but certain to have bugs and rough edges; hopefully it’s good enough to envision what you’d really like the application to do and be motivated to provide feedback. If you find a bug, please report it.
Experience suggests that feedback will direct the app’s evolution in directions that are hard to imagine at this point. It’s best to avoid getting too attached to any specific feature designs yet.
The application should let you perform basic editing of typical Origami projects:
- Install the application on macOS with Apple silicon.
- Issue Origami commands and see the result instantly appear in the result pane.
- Edit a text file in the Monaco editor, the same editor used by Microsoft VS Code.
- Change a file and see the result automatically reload.
- If the displayed HTML contains links, browse within the local site.
- Use Back/Forward buttons to navigate command results.
- Standard file tab behavior common in IDEs (drag and drop, Close to Right, etc.)
- Adjusting or disabling auto-save or auto-reload
- Directly specifying the default site for a project
- Window or Linux versions
- Dark mode
- Context menus
- Resizing the 50/50 split of the window panes
- Reloading project settings if you edit
config.oriorpackage.jsoninside the app; you’ll need to close the window and then reopen it to see the changes - In-app File Explorer
- LSP integration for inline errors and other language integration features
- Selectable views (YAML, JSON, SVG diagram, etc.)
- Reloading JavaScript modules (other than ones directly loaded by Origami, just like
ori serve watchdoes) - JavaScript module isolation. All modules for all project windows are loaded in a single Node application space; if one project loads JavaScript that manipulates global state, that might interfere with the running of a project in a different window.
- Build, serve, or deploy a site
- Help
Projector’s user model is organized around projects: a folder tree of related files, generally identified by its root; see below.
Within a project, Projector can edit text files: plain text, markdown, CSS, JSON, YAML, JavaScript, Origami, etc. Files are always viewed in the context of a project.
When you open a file or folder, Projector establishes its associated root folder based on the file/folder’s location:
- From the location, Projector walks up the folder hierarchy looking for an Origami configuration file called
config.ori. If found, the folder containing that file is the project root. Note: anorigamiproject may also have apackage.jsonat the root level. - From the location, Projector walks up the folder hierarchy looking for an npm
package.jsonfile. If found, the folder containing that file is the project root. - Otherwise, the file’s containing folder is the project root; or, if the given object was a folder, the folder itself is the project root.
A project’s name is used as a way to identify the project in window title bars and the Open Recent Project submenu.
- For a project with a package.json at its root, the project name is the
namefield from that file. - Otherwise the friendly name is the name of the project’s root folder. E.g., for
/Users/Alice/hello, the project name is “hello”.
Each project can be associated with a default site: a tree of resources used to handle absolute local URLs.
If you render an HTML page, it may reference stylesheets, scripts, or other resources with absolute paths like /assets/styles.css. Projector needs to load those resources from somewhere — and there may not be any obvious connection between the command (or the active file) and the location of those resources.
Therefore, Projector loads such absolute local URLs from the project’s default site, which it finds with the following heuristic:
-
If the project contains a package.json file with
scripts, Projector searches thedev,serve,start, orbuildscripts (in that order) for the first script that references an.orifile. That.orifile will be loaded as the project’s default site. For example, if the script follows the standard incantation to start a server, then the project’s default site will be the same as the one you normally start withnpm run start. -
If such a site path can’t be found, the project’s default site will be the project’s root folder. That is, absolute local URLs paths will be resolved with the root folder as the root of the site.
When you start Projector, it restores the project windows that were open when you last quit the application, skipping any project whose root folder no longer exists. Reopening projects is viewed as a non-critical user convenience; even if none of the previous projects exist, no message is shown.
When reopening a project window, Projector attempts to restore the state of the window when you closed it:
- It reopens the most recently opened file.
- It shows the most recently run command in the command bar.
- If in the last session that most recent command had completed without hanging or crashing, then Projector re-runs that command and displays the result. Otherwise Projector does not run it to avoid a cycle of crashes.
Projector persists the following settings:
- paths of recent projects
- paths of projects which were open when the application was closed
- paths of the recent files opened within each project
- recent commands used within each project
- editor options (see Options menu)
These settings are saved whenever their values change.
Projector registers itself as a handler for the .ori file extension. Double-clicking a file in a folder window should open the project for that file, then open the file in the editor.
On macOS it doesn't appear possible to register a handler for combination extensions like .ori.html.
Projector will detect if you edit project files outside the application and reload both the editing area and the result pane. This lets you use Projector in parallel with other tools.
Externally editing certain files have additional effects:
- External edits to
package.jsonorconfig.orireload the project. This will pick up changes in, for example, project name or default site. - External edits to the project’s default site file (e.g.,
src/site.ori) will cause the site to be reloaded.
The application menu bar offers the standard commands for a text editor.
- Open Project Folder…. Shows a standard File Open dialog to pick an existing folder.
- Open Recent Project. A submenu showing the friendly names of recently opened projects.
- Close. Closes the current project window.
- New File. Clears the text editor.
- Open File…. Shows a standard File Open dialog to pick an existing file.
- Save File. This is generally not needed as Projector auto-saves. This item exists primarily to support the corresponding standard keyboard shortcut, which is useful when editing a new file.
- Save File As…. Shows a standard File Save As dialog.
Opening a folder via the Open menu implies opening the project for the project’s root (see project root, above). If that project is already open in a window, that project window is made active. Otherwise the folder opens in a new window for that project.
The Open Recent Project submenu shows the friendly names of the 10 most recently opened projects. The submenu also includes a "Clear Menu" command to clear the recent projects list. Selecting a project from this submenu opens it. If the project path no longer exists, an error message indicates this, and the project is removed from the recent projects menu.
Using Save As to save a file outside of the project’s folder tree will save that text to the indicated location and open a new project window (or open an existing one) for the project rooted at the new location.
The menu bar shows a stock Edit menu with the usual commands: Cut, Copy, Paste, etc.
- Home. Runs the command that will show the project’s root.
- Back. Backs up to the last command and reruns it.
- Forward. Navigates forward in the command history.
- Toggle Developer Tools. Shows standard Chromium Dev Tools.
The Back/Forward buttons generally emulate standard browser behavior with a back/forward stack.
These reflect various Monaco editor preferences:
-Auto-Close Brackets. If checked, typing an opening bracket (([{) automatically types the corresponding closing bracket. Default: checked. -Indentation submenu. The first group of items lets you choose between 2 (default), 4, or 8 spaces of indentation. The second group lets you choose between indenting with spaces (true) or tabs. -Show Line Numbers. If checked, line numbers are shown. Default is unchecked.
The Window menu is a stock menu with the usual commands: Minimize, etc.
In addition to the menu item keyboard shortcuts, Projector supports:
- Command+L: Moves the focus to the command area and selects the command text.
Each open project is represented by a single window. The window title bar shows the project’s friendly name.
The window is divided into a 2x2 grid:
- Recent bar in upper left
- Editing area in main part of left side
- Command bar in upper right
- Result pane in main part of right side
Projector tracks the 10 most recently opened files for a given project. These are rendered as tabs across the top of the editing area. The recent bar shows as many tabs as can fit horizontally; the remainder are clipped.
Each tab displays the name of the associated file, or "Untitled" if the file has not been saved yet.
The active file is always the most recent one, and always shown in the leftmost tab. Opening another file in the project (via File / Open, or by clicking a different tab) makes that new file the recent file, and therefore the active and leftmost tab.
If you have made changes to a new file but not saved it, attempting to open another file will display a Yes/No/Cancel dialog prompting you to save the changes.
If you select a recent file from the tab bar and that file no longer exists, the tab for that file is removed.
It is possible to have no file open and hence no file tabs visible.
The editing area is an instance of the Monaco code editor.
You can adjust a small number of Monaco editor options through the Options menu (above). Beyond that, the editor is left in its default configuration.
While the editor has focus, pressing F1 displays a palette of editing commands.
When you type into the editing area for an existing file, after a short (subsecond) delay Projector automatically saves the edits; it is not necessary to use a Save command.
If you are working in a new file, your edits will not be saved until you use the File → Save File As command to save the file.
Stopgap: It’s possible to edit package.json and config.ori in Projector — but edits you make to those files within the application will not trigger a reload of the project. Reloading is a somewhat expensive operation, and deemed too hard to support with auto-save. You will need to close the project window and reopen it to reload the project with those changes.
A single line text box in the upper right lets you enter Origami commands. These are parsed and evaluated as with the ori CLI. (Because you are not working inside of a shell program, e.g., bash, you don’t have to worry about a shell parser parsing things. Among other things, you don’t have to quote parentheses.)
When you open a project for the first time, if the project has a default site, then the default command will evaluate that site. E.g., if the default site is defined in src/site.ori, then the default command will be src/site.ori/. This will generally cause the site’s default index.html page to appear.
When the keyboard focus is in the command bar, pressing Return evaluates the current command in the context of the project root folder. (An empty command does nothing.)
Each project records the most recent commands for that project. Issuing a command makes it the most recent command. Note that this most-recently used list is related to, but distinct from, the back/forward stacks used by the Back/Forward buttons.
While the command bar has focus, you can press the Up or Down arrow keys to navigate to, respectively, the previous or next command in the recent command list.
Back and Forward buttons like you navigate your command history in the same way you can navigate web history in a browser.
The result pane shows the result of the most recently-issued command: an HTML page, text file, etc.
If the result is an image, Projector renders it roughly the same way Chrome does: the image is shown on a black background, and the image width is constrained to the width of the result pane.
If a command results in an error (exception), the result pane is not updated. Instead, an error pane will appear over the top of the result pane and show the error message. The command bar will also change color to emphasize the error state.
Once the error has been resolved, the error pane will disappear, the result pane will show the new result, and the command bar will revert to its normal color.
Whenever the active file is saved, after a short delay the result pane will reload to show any effects of the edits.
Before reloading, Projector saves the scroll position of all scrollable elements on the page. After the result pane reloads, if the command and result path have stayed the same (i.e., you are not navigating), then Projector attempts to restore the scroll position of those elements. The goal is to let you continue viewing the same area of the page you were looking at previously.
If you click a link in an HTML result:
- An external link opens in your default browser.
- An internal link is intercepted and handled by modifying the current command. E.g., if the current command is
src/site.ori/and you click a link to “about.html”, Projector updates the command tosrc/site.ori/about.htmland then runs that.
If the main application suffers a top-level unexpected error, it displays an error dialog. It also saves an error report in ~/Library/Application Support/Origami Projector/error.log.
Projector is an Electron application, so includes both the Node runtime and the Chromium browser engine.
Some important pieces:
- Main process. This defines overall application behavior, including startup and shutdown.
- Project. An object representing the state of an open project.
- Project window. There is one Electron window for each open project.
- Session. Each project window has an associated browser session.
- Renderer. Each project window has an associated renderer process that can communicate with the main application or, through it, with the associated project or session.
- Client page. The content of each project window is defined with an HTML page that loads client-side JavaScript.
- The @weborigami/origami package has a dependency on "sharp", which has an optional dependency on "@emnapi/runtime". There are known issues using sharp in Electron; it appears that npm doesn't always install the @emnapi/runtime package, which causes electron-builder to fail. The package.json contains several workarounds for this, including explicitly installing @emnapi/runtime and sharp; setting
asaroptions to unpack these packages; and using thenpmRebuildandbuildDependenciesFromSourceoptions. It would be nice to find a cleaner solution in the future.