Skip to main content

Working on the documentation

This site lives in website/ and is built with Docusaurus 3. Part of it is hand-written, part is generated from the Haxe sources so it cannot drift.

Running it locally​

cd website
npm install
npm start # dev server with hot reload on http://localhost:3000
npm run build # production build into website/build
npm run serve # serve the production build

npm start and npm run build both regenerate the derived pages first (see prestart / prebuild in package.json), so the reference is always current.

Layout​

website/
├── docs/
│ ├── intro.md
│ ├── getting-started/ hand-written
│ ├── architecture/ hand-written
│ ├── subsystems/ hand-written
│ ├── modding/ hand-written + 2 generated pages
│ ├── contributing/ hand-written
│ └── reference/ GENERATED — do not edit
├── scripts/
│ ├── haxe-parser.mjs minimal Haxe parser (no dependencies)
│ ├── generate-api-docs.mjs source/**.hx → docs/reference/**
│ ├── generate-script-api.mjs psychlua/** → the Lua/Python API pages
│ └── check-doc-syntax.mjs lint: admonitions and other silent render failures
├── src/ theme customisation and the landing page
├── static/img/ logo and favicon
├── docusaurus.config.js
└── sidebars.js one autogenerated sidebar from the folder tree

The generators​

CommandReadsWrites
npm run gen:apisource/**/*.hxdocs/reference/** (one page per type, one index per package)
npm run gen:scriptssource/psychlua/**docs/modding/lua-api-reference.md, docs/modding/python-api-reference.md
npm run genbothboth

How the API generator works​

scripts/haxe-parser.mjs is a small lexical parser — it does not type-check, it extracts shape. For every module it records the package, imports, types (class, interface, enum, abstract, typedef), inheritance, fields, methods with full signatures, enum values, structure fields, metadata, and the #if stack active at each declaration.

scripts/generate-api-docs.mjs renders that into markdown: a fact table, the doc comment, known subclasses, public fields, public methods with parameter tables and a GitHub source link per member, and a collapsed Internals section for private members. Package descriptions come from the PACKAGE_INFO table at the top of that file — add an entry when you add a package.

How the script-API generator works​

scripts/generate-script-api.mjs scans for registerFunction("name", function(...)) in source/psychlua/, splitting Lua (callbacks/) from Python (pystdlib/). It uses the parameter list for the signature and the // comment block directly above the registration as the description, then groups functions by their source module using the GROUPS table.

Document a callback from the engine

Put a // comment immediately above registerFunction(...) and it becomes the function's description on the reference page. The same is true for /** ... */ on Haxe types and fields.

Adding a page​

  1. Create a markdown file in the right docs/ folder.

  2. Give it front matter:

    ---
    title: My page
    sidebar_position: 7
    description: One sentence for search engines and the category index.
    ---
  3. The sidebar is autogenerated from the folder tree, so nothing else is needed. Category labels and ordering come from each folder's _category_.json.

Markdown gotchas​

docusaurus.config.js sets markdown.format: 'detect', so .md files are parsed as CommonMark and only .mdx files as MDX. That is what lets the generated pages print Haxe generics (Array<Foo>) literally, but it also means MDX-only conveniences are unavailable in .md:

  • { and < can still be read as expressions/JSX in .mdx — wrap identifiers in backticks.
  • Inside tables, escape | as \|.
  • The generators already handle both for generated content.

Admonitions (the coloured notices)​

future.v4 disables the MDX-v1 compatibility layer, so the old space-separated title is not recognised any more — :::info Generated page builds without an error and shows the raw colons as a paragraph. Use the directive-label form, with a plain-text title, and keep a blank line after the opening fence and before the closing one:

:::info[Generated page]

Some **content** here.

:::

Three rules for .md files:

DoBecause
:::tip[Title], never :::tip Titleonly the directive label is parsed once mdx1Compat is off
Keep titles plain text (no `code`, no <, no {})a complex title leaks a raw <mdxAdmonitionTitle> tag in CommonMark
Leave the body fenced by blank linesPrettier otherwise reflows the block into something invalid

npm run lint:docs (website/scripts/check-doc-syntax.mjs) enforces all three and runs as part of prebuild and in the docs workflow, so a notice that would render as plain text fails the build instead of shipping.

Deployment​

.github/workflows/docs.yml builds the site and publishes it to GitHub Pages on pushes to main that touch website/, source/ or the root documentation files — and manually via workflow_dispatch. Because the reference is regenerated during the build, a change to a Haxe doc comment updates the published site with no extra step.

The site is served from https://havaianasdestruido.github.io/FNF-Phoenix-Engine/; the url and baseUrl live in docusaurus.config.js.

When to update what​

You changedUpdate
A Haxe doc commentnothing — regenerate
A new packagePACKAGE_INFO in generate-api-docs.mjs
A new Lua/Python callbacknothing — regenerate (add a // comment for a description)
A build flagProject configuration
A subsystem's behaviourthe matching page in docs/subsystems/
A haxelib patchHaxelib patches and BUILDING.md