Skip to main content

Template Conventions

Generated and templated files (Luau scripts, Rojo projects, etc.) follow a consistent layout across CLI tools.

Directory layout​

All template files live in a templates/ directory at the root of the tool package that owns them:

tools/nevermore-cli/templates/
batch-test-runner.lua # Batch test execution script
game-template/ # Game scaffolding
nevermore-library-package-template/ # Package scaffolding
nevermore-service-package-template/ # Service package scaffolding
plugin-template/ # Plugin scaffolding

tools/studio-bridge/templates/ # Studio bridge plugin template

Placeholder pattern​

Templates use {{PLACEHOLDER}} syntax for values filled in at runtime. The double-brace pattern is distinct from Lua/Luau syntax, making placeholders easy to find and unlikely to collide with real code.

Example from batch-test-runner.lua:

local packageSlugs = {{PACKAGE_SLUGS}}

Replaced at runtime with:

local packageSlugs = { "maid", "blend", "roguehumanoid" }

Resolving template paths​

Use resolveTemplatePath from @quenty/nevermore-template-helpers to resolve template paths at runtime. It finds the calling package's root (via package.json) and appends templates/<name>:

import { resolveTemplatePath } from '@quenty/nevermore-template-helpers';

const templatePath = resolveTemplatePath(import.meta.url, 'batch-test-runner.lua');

This works regardless of where the compiled JS ends up relative to the source.

CI workflows​

Game and plugin templates include GitHub Actions workflows for linting, testing, and deployment. These use npx @quenty/nevermore-cli (not building from source) since the CLI is published to npm as a public package.

  • Linting — Each linter job pipes output through tee and posts inline PR annotations via nevermore tools post-lint-results. Since templates have node available in every job, annotations are posted inline (no artifact relay needed).
  • Tests / Deploy — These workflows use a config-check job that tests whether ROBLOX_OPEN_CLOUD_API_KEY is set. If not, the main job is skipped (shows "Skipped" in GitHub UI) and a ::notice annotation explains setup. This means newly scaffolded projects have zero failing workflows until the user deliberately enables testing/deploy.

All ${{ }} GitHub Actions expressions are written as $\{{ }} in template files to prevent Handlebars from interpreting them during scaffolding.