Skip to content

CodeSignal/learn_latex

Repository files navigation

learn-latex

Browser-based LaTeX editor with live preview, built for CodeSignal. Learners edit .tex files in CodeMirror on the left; latex.js renders the preview on the right.

Run

npm install
npm run dev                       # Vite dev server on :5173
npm run build                     # Build to dist/
IS_PRODUCTION=true npm start      # Serve dist/ + API on :3000 (PORT to override)

Configuration

config.json is read on every /config request, so changes take effect on reload.

Key Type Description
starterFiles { filename: contents } Initial .tex files
readOnlyFiles string[] Files the learner can't rename or delete
activeFile string File open at startup
sidebarExpanded boolean Whether the file panel starts visible

Filenames must match ^[A-Za-z0-9][A-Za-z0-9 _.-]*\.tex$.

API

The server keeps session state in memory. There is no persistence and no auth — the container is single-user.

Method Path Purpose
GET /config Returns config.json.
GET /snapshot, /content Current learner state — see schema below.
POST /snapshot Frontend pushes state. Not for external callers.
GET /images Image metadata (name, url, mime, size).
GET /image/:name Image bytes.
PUT /images/:name Upload raw bytes with Content-Type: image/*.
POST /images/fetch Body { name, url } — server downloads url and stores it.
DELETE /images/:name Remove an image.

Limits: 5 MB per image, 20 images total, 2 MB per JSON body.

Snapshot schema (grader contract)

{
  "files": { "main.tex": "\\documentclass{article}..." },
  "activeFile": "main.tex",
  "lastRenderResult": {
    "ok": true,
    "error": null,
    "file": "main.tex",
    "timestamp": "2026-06-04T12:00:00.000Z"
  }
}

lastRenderResult is one of:

  • null — no render result yet for the current files / activeFile. The learner just edited, switched, renamed, created, or deleted a file and the next render hasn't completed. Poll again.
  • { ok: true, ... } — the file in file rendered successfully.
  • { ok: false, error, ... } — render failed; error is the message.

Graders should treat lastRenderResult === null as "retry, render is pending" — never as success or failure.

Layout

src/
  main.js              app bootstrap, state, snapshot sync
  editor.js            CodeMirror setup
  editorToolbar.js     formatting buttons above the editor
  filetree.js          file/image sidebar
  imageUpload.js       upload modal
  modal.js             generic modal
  outline.js           section outline
  preprocess.js        LaTeX-source rewrites for latex.js compatibility
  preview.js           latex.js render + pagination
  previewControls.js   compile / page / zoom toolbar
server.js              Express 5 API + static prod server
vite.config.js         Vite + dev-mode API shim
config.json            Per-lesson starter files & flags

Release

.github/workflows/release.yml builds on push to main and uploads release.tar.gz (containing dist/, server.js, package.json, package-lock.json, config.json, node_modules) as a GitHub release tagged with the commit SHA.

About

Browser-based LaTeX editor

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors