gethtmlpress 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md ADDED
@@ -0,0 +1,9 @@
1
+ # The MIT License (MIT)
2
+
3
+ Copyright © 2026 Evgeny Karev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,49 @@
1
- # Temporary Holding Version
1
+ # Htmlpress
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Htmlpress turns a folder of HTML pages into a site. Each page keeps its own markup, and
4
+ htmlpress adds one layout, one theme, a navigation and a live-reloading dev server. It is
5
+ made for coding agents: they write plain semantic HTML, and the result looks consistent
6
+ without a framework, a build config or Tailwind.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install --global gethtmlpress
12
+ # or run it without installing
13
+ npx gethtmlpress build docs
14
+ ```
15
+
16
+ The package carries a prebuilt binary for Linux, macOS and Windows (x64 and arm64)
17
+ through a platform-specific optional dependency; no Rust toolchain is needed.
18
+
19
+ ## Usage
20
+
21
+ ```bash
22
+ htmlpress build docs # render docs/ into docs/.htmlpress/build
23
+ htmlpress start docs # serve it on http://localhost:8000, rebuilding on save
24
+ htmlpress build docs --json # the result as JSON, for scripts and agents
25
+ htmlpress --llms # every command's input and output schema, for agents
26
+ ```
27
+
28
+ A page is any `.html` file in the folder: a full document or just a fragment. Its `<title>`
29
+ (else its first `<h1>`) names it in the navigation, `<meta name="order" content="1">` sorts it,
30
+ and `index.html` comes first. Every other file is copied as-is.
31
+
32
+ ```html
33
+ <title>Getting started</title>
34
+ <meta name="order" content="1" />
35
+
36
+ <h1>Getting started</h1>
37
+ <p>Plain HTML, styled by the built-in theme.</p>
38
+ <htmlpress-callout type="warning"
39
+ ><p>Light-DOM components cover what HTML lacks.</p></htmlpress-callout
40
+ >
41
+ ```
42
+
43
+ ## Documentation
44
+
45
+ Read the docs at [htmlpress.dev](https://htmlpress.dev), themselves built with htmlpress.
46
+
47
+ ## License
48
+
49
+ MIT.
@@ -0,0 +1,7 @@
1
+ /** Find the htmlpress binary: the env override first, else the matching platform package. */
2
+ export declare function resolveBinary(props: {
3
+ platform: string;
4
+ arch: string;
5
+ env: Record<string, string | undefined>;
6
+ resolvePackage: (specifier: string) => string;
7
+ }): string;
@@ -0,0 +1,22 @@
1
+ import { BINARY_ENV, PACKAGE_NAME, PLATFORMS } from "../../settings.js";
2
+ /** Find the htmlpress binary: the env override first, else the matching platform package. */
3
+ export function resolveBinary(props) {
4
+ const override = props.env[BINARY_ENV];
5
+ if (override)
6
+ return override;
7
+ const key = `${props.platform}-${props.arch}`;
8
+ const platform = PLATFORMS[key];
9
+ if (!platform) {
10
+ const supported = Object.keys(PLATFORMS).join(", ");
11
+ throw new Error(`${PACKAGE_NAME} has no binary for ${key}; supported: ${supported}. ` +
12
+ `Set ${BINARY_ENV} to a binary built with cargo to run it anyway.`);
13
+ }
14
+ try {
15
+ return props.resolvePackage(`${platform.packageName}/bin/${platform.binary}`);
16
+ }
17
+ catch {
18
+ throw new Error(`${platform.packageName} is not installed. Reinstall ${PACKAGE_NAME} without ` +
19
+ `--no-optional / --omit=optional so the binary for ${key} comes along.`);
20
+ }
21
+ }
22
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVzb2x2ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2FjdGlvbnMvYmluYXJ5L3Jlc29sdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQUUsU0FBUyxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFFdkUsNkZBQTZGO0FBQzdGLE1BQU0sVUFBVSxhQUFhLENBQUMsS0FLN0I7SUFDQyxNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFBO0lBQ3RDLElBQUksUUFBUTtRQUFFLE9BQU8sUUFBUSxDQUFBO0lBRTdCLE1BQU0sR0FBRyxHQUFHLEdBQUcsS0FBSyxDQUFDLFFBQVEsSUFBSSxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUE7SUFDN0MsTUFBTSxRQUFRLEdBQUcsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFBO0lBQy9CLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNkLE1BQU0sU0FBUyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFBO1FBQ25ELE1BQU0sSUFBSSxLQUFLLENBQ2IsR0FBRyxZQUFZLHNCQUFzQixHQUFHLGdCQUFnQixTQUFTLElBQUk7WUFDbkUsT0FBTyxVQUFVLGlEQUFpRCxDQUNyRSxDQUFBO0lBQ0gsQ0FBQztJQUNELElBQUksQ0FBQztRQUNILE9BQU8sS0FBSyxDQUFDLGNBQWMsQ0FBQyxHQUFHLFFBQVEsQ0FBQyxXQUFXLFFBQVEsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUE7SUFDL0UsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLE1BQU0sSUFBSSxLQUFLLENBQ2IsR0FBRyxRQUFRLENBQUMsV0FBVyxnQ0FBZ0MsWUFBWSxXQUFXO1lBQzVFLHFEQUFxRCxHQUFHLGVBQWUsQ0FDMUUsQ0FBQTtJQUNILENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQklOQVJZX0VOViwgUEFDS0FHRV9OQU1FLCBQTEFURk9STVMgfSBmcm9tIFwiLi4vLi4vc2V0dGluZ3MudHNcIlxuXG4vKiogRmluZCB0aGUgaHRtbHByZXNzIGJpbmFyeTogdGhlIGVudiBvdmVycmlkZSBmaXJzdCwgZWxzZSB0aGUgbWF0Y2hpbmcgcGxhdGZvcm0gcGFja2FnZS4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlQmluYXJ5KHByb3BzOiB7XG4gIHBsYXRmb3JtOiBzdHJpbmdcbiAgYXJjaDogc3RyaW5nXG4gIGVudjogUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgdW5kZWZpbmVkPlxuICByZXNvbHZlUGFja2FnZTogKHNwZWNpZmllcjogc3RyaW5nKSA9PiBzdHJpbmdcbn0pIHtcbiAgY29uc3Qgb3ZlcnJpZGUgPSBwcm9wcy5lbnZbQklOQVJZX0VOVl1cbiAgaWYgKG92ZXJyaWRlKSByZXR1cm4gb3ZlcnJpZGVcblxuICBjb25zdCBrZXkgPSBgJHtwcm9wcy5wbGF0Zm9ybX0tJHtwcm9wcy5hcmNofWBcbiAgY29uc3QgcGxhdGZvcm0gPSBQTEFURk9STVNba2V5XVxuICBpZiAoIXBsYXRmb3JtKSB7XG4gICAgY29uc3Qgc3VwcG9ydGVkID0gT2JqZWN0LmtleXMoUExBVEZPUk1TKS5qb2luKFwiLCBcIilcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgJHtQQUNLQUdFX05BTUV9IGhhcyBubyBiaW5hcnkgZm9yICR7a2V5fTsgc3VwcG9ydGVkOiAke3N1cHBvcnRlZH0uIGAgK1xuICAgICAgICBgU2V0ICR7QklOQVJZX0VOVn0gdG8gYSBiaW5hcnkgYnVpbHQgd2l0aCBjYXJnbyB0byBydW4gaXQgYW55d2F5LmAsXG4gICAgKVxuICB9XG4gIHRyeSB7XG4gICAgcmV0dXJuIHByb3BzLnJlc29sdmVQYWNrYWdlKGAke3BsYXRmb3JtLnBhY2thZ2VOYW1lfS9iaW4vJHtwbGF0Zm9ybS5iaW5hcnl9YClcbiAgfSBjYXRjaCB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYCR7cGxhdGZvcm0ucGFja2FnZU5hbWV9IGlzIG5vdCBpbnN0YWxsZWQuIFJlaW5zdGFsbCAke1BBQ0tBR0VfTkFNRX0gd2l0aG91dCBgICtcbiAgICAgICAgYC0tbm8tb3B0aW9uYWwgLyAtLW9taXQ9b3B0aW9uYWwgc28gdGhlIGJpbmFyeSBmb3IgJHtrZXl9IGNvbWVzIGFsb25nLmAsXG4gICAgKVxuICB9XG59XG4iXX0=
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+ import { spawnSync } from "node:child_process";
3
+ import { createRequire } from "node:module";
4
+ import { resolveBinary } from "../actions/binary/resolve.js";
5
+ const require = createRequire(import.meta.url);
6
+ let binary;
7
+ try {
8
+ binary = resolveBinary({
9
+ platform: process.platform,
10
+ arch: process.arch,
11
+ env: process.env,
12
+ resolvePackage: specifier => require.resolve(specifier),
13
+ });
14
+ }
15
+ catch (error) {
16
+ console.error(`error: ${error instanceof Error ? error.message : String(error)}`);
17
+ process.exit(1);
18
+ }
19
+ const result = spawnSync(binary, process.argv.slice(2), { stdio: "inherit" });
20
+ if (result.error) {
21
+ console.error(`error: cannot run ${binary}: ${result.error.message}`);
22
+ process.exit(1);
23
+ }
24
+ // Re-raise a signal so a parent sees the same death the binary had (Ctrl-C under start)
25
+ if (result.signal)
26
+ process.kill(process.pid, result.signal);
27
+ process.exit(result.status ?? 1);
28
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL2VudHJ5cG9pbnRzL21haW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUNBLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQTtBQUM5QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQzNDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQTtBQUU1RCxNQUFNLE9BQU8sR0FBRyxhQUFhLENBQUMsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUE7QUFFOUMsSUFBSSxNQUFjLENBQUE7QUFDbEIsSUFBSSxDQUFDO0lBQ0gsTUFBTSxHQUFHLGFBQWEsQ0FBQztRQUNyQixRQUFRLEVBQUUsT0FBTyxDQUFDLFFBQVE7UUFDMUIsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJO1FBQ2xCLEdBQUcsRUFBRSxPQUFPLENBQUMsR0FBRztRQUNoQixjQUFjLEVBQUUsU0FBUyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQztLQUN4RCxDQUFDLENBQUE7QUFDSixDQUFDO0FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztJQUNmLE9BQU8sQ0FBQyxLQUFLLENBQUMsVUFBVSxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFBO0lBQ2pGLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUE7QUFDakIsQ0FBQztBQUVELE1BQU0sTUFBTSxHQUFHLFNBQVMsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQTtBQUM3RSxJQUFJLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUNqQixPQUFPLENBQUMsS0FBSyxDQUFDLHFCQUFxQixNQUFNLEtBQUssTUFBTSxDQUFDLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFBO0lBQ3JFLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUE7QUFDakIsQ0FBQztBQUNELHdGQUF3RjtBQUN4RixJQUFJLE1BQU0sQ0FBQyxNQUFNO0lBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQTtBQUMzRCxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLElBQUksQ0FBQyxDQUFDLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyIjIS91c3IvYmluL2VudiBub2RlXG5pbXBvcnQgeyBzcGF3blN5bmMgfSBmcm9tIFwibm9kZTpjaGlsZF9wcm9jZXNzXCJcbmltcG9ydCB7IGNyZWF0ZVJlcXVpcmUgfSBmcm9tIFwibm9kZTptb2R1bGVcIlxuaW1wb3J0IHsgcmVzb2x2ZUJpbmFyeSB9IGZyb20gXCIuLi9hY3Rpb25zL2JpbmFyeS9yZXNvbHZlLnRzXCJcblxuY29uc3QgcmVxdWlyZSA9IGNyZWF0ZVJlcXVpcmUoaW1wb3J0Lm1ldGEudXJsKVxuXG5sZXQgYmluYXJ5OiBzdHJpbmdcbnRyeSB7XG4gIGJpbmFyeSA9IHJlc29sdmVCaW5hcnkoe1xuICAgIHBsYXRmb3JtOiBwcm9jZXNzLnBsYXRmb3JtLFxuICAgIGFyY2g6IHByb2Nlc3MuYXJjaCxcbiAgICBlbnY6IHByb2Nlc3MuZW52LFxuICAgIHJlc29sdmVQYWNrYWdlOiBzcGVjaWZpZXIgPT4gcmVxdWlyZS5yZXNvbHZlKHNwZWNpZmllciksXG4gIH0pXG59IGNhdGNoIChlcnJvcikge1xuICBjb25zb2xlLmVycm9yKGBlcnJvcjogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YClcbiAgcHJvY2Vzcy5leGl0KDEpXG59XG5cbmNvbnN0IHJlc3VsdCA9IHNwYXduU3luYyhiaW5hcnksIHByb2Nlc3MuYXJndi5zbGljZSgyKSwgeyBzdGRpbzogXCJpbmhlcml0XCIgfSlcbmlmIChyZXN1bHQuZXJyb3IpIHtcbiAgY29uc29sZS5lcnJvcihgZXJyb3I6IGNhbm5vdCBydW4gJHtiaW5hcnl9OiAke3Jlc3VsdC5lcnJvci5tZXNzYWdlfWApXG4gIHByb2Nlc3MuZXhpdCgxKVxufVxuLy8gUmUtcmFpc2UgYSBzaWduYWwgc28gYSBwYXJlbnQgc2VlcyB0aGUgc2FtZSBkZWF0aCB0aGUgYmluYXJ5IGhhZCAoQ3RybC1DIHVuZGVyIHN0YXJ0KVxuaWYgKHJlc3VsdC5zaWduYWwpIHByb2Nlc3Mua2lsbChwcm9jZXNzLnBpZCwgcmVzdWx0LnNpZ25hbClcbnByb2Nlc3MuZXhpdChyZXN1bHQuc3RhdHVzID8/IDEpXG4iXX0=
@@ -0,0 +1,14 @@
1
+ export interface Platform {
2
+ /** The npm package that carries this platform's binary. */
3
+ packageName: string;
4
+ /** The Rust target the binary is compiled for. */
5
+ target: string;
6
+ /** The binary's file name inside the package's `bin/`. */
7
+ binary: string;
8
+ }
9
+ /** The npm package users install; it pulls in the one platform package that matches. */
10
+ export declare const PACKAGE_NAME = "gethtmlpress";
11
+ /** An environment variable that points at a binary to run instead of the installed one. */
12
+ export declare const BINARY_ENV = "HTMLPRESS_BINARY";
13
+ /** Every published platform, keyed by `${process.platform}-${process.arch}`. */
14
+ export declare const PLATFORMS: Record<string, Platform>;
@@ -0,0 +1,18 @@
1
+ /** The npm package users install; it pulls in the one platform package that matches. */
2
+ export const PACKAGE_NAME = "gethtmlpress";
3
+ /** An environment variable that points at a binary to run instead of the installed one. */
4
+ export const BINARY_ENV = "HTMLPRESS_BINARY";
5
+ /** Every published platform, keyed by `${process.platform}-${process.arch}`. */
6
+ export const PLATFORMS = {
7
+ "linux-x64": createPlatform("linux-x64", "x86_64-unknown-linux-musl"),
8
+ "linux-arm64": createPlatform("linux-arm64", "aarch64-unknown-linux-musl"),
9
+ "darwin-x64": createPlatform("darwin-x64", "x86_64-apple-darwin"),
10
+ "darwin-arm64": createPlatform("darwin-arm64", "aarch64-apple-darwin"),
11
+ "win32-x64": createPlatform("win32-x64", "x86_64-pc-windows-msvc"),
12
+ "win32-arm64": createPlatform("win32-arm64", "aarch64-pc-windows-msvc"),
13
+ };
14
+ function createPlatform(key, target) {
15
+ const binary = key.startsWith("win32") ? "htmlpress.exe" : "htmlpress";
16
+ return { packageName: `@htmlpress/${key}`, target, binary };
17
+ }
18
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2V0dGluZ3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zZXR0aW5ncy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFTQSx3RkFBd0Y7QUFDeEYsTUFBTSxDQUFDLE1BQU0sWUFBWSxHQUFHLGNBQWMsQ0FBQTtBQUUxQywyRkFBMkY7QUFDM0YsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHLGtCQUFrQixDQUFBO0FBRTVDLGdGQUFnRjtBQUNoRixNQUFNLENBQUMsTUFBTSxTQUFTLEdBQTZCO0lBQ2pELFdBQVcsRUFBRSxjQUFjLENBQUMsV0FBVyxFQUFFLDJCQUEyQixDQUFDO0lBQ3JFLGFBQWEsRUFBRSxjQUFjLENBQUMsYUFBYSxFQUFFLDRCQUE0QixDQUFDO0lBQzFFLFlBQVksRUFBRSxjQUFjLENBQUMsWUFBWSxFQUFFLHFCQUFxQixDQUFDO0lBQ2pFLGNBQWMsRUFBRSxjQUFjLENBQUMsY0FBYyxFQUFFLHNCQUFzQixDQUFDO0lBQ3RFLFdBQVcsRUFBRSxjQUFjLENBQUMsV0FBVyxFQUFFLHdCQUF3QixDQUFDO0lBQ2xFLGFBQWEsRUFBRSxjQUFjLENBQUMsYUFBYSxFQUFFLHlCQUF5QixDQUFDO0NBQ3hFLENBQUE7QUFFRCxTQUFTLGNBQWMsQ0FBQyxHQUFXLEVBQUUsTUFBYztJQUNqRCxNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQTtJQUN0RSxPQUFPLEVBQUUsV0FBVyxFQUFFLGNBQWMsR0FBRyxFQUFFLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxDQUFBO0FBQzdELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgaW50ZXJmYWNlIFBsYXRmb3JtIHtcbiAgLyoqIFRoZSBucG0gcGFja2FnZSB0aGF0IGNhcnJpZXMgdGhpcyBwbGF0Zm9ybSdzIGJpbmFyeS4gKi9cbiAgcGFja2FnZU5hbWU6IHN0cmluZ1xuICAvKiogVGhlIFJ1c3QgdGFyZ2V0IHRoZSBiaW5hcnkgaXMgY29tcGlsZWQgZm9yLiAqL1xuICB0YXJnZXQ6IHN0cmluZ1xuICAvKiogVGhlIGJpbmFyeSdzIGZpbGUgbmFtZSBpbnNpZGUgdGhlIHBhY2thZ2UncyBgYmluL2AuICovXG4gIGJpbmFyeTogc3RyaW5nXG59XG5cbi8qKiBUaGUgbnBtIHBhY2thZ2UgdXNlcnMgaW5zdGFsbDsgaXQgcHVsbHMgaW4gdGhlIG9uZSBwbGF0Zm9ybSBwYWNrYWdlIHRoYXQgbWF0Y2hlcy4gKi9cbmV4cG9ydCBjb25zdCBQQUNLQUdFX05BTUUgPSBcImdldGh0bWxwcmVzc1wiXG5cbi8qKiBBbiBlbnZpcm9ubWVudCB2YXJpYWJsZSB0aGF0IHBvaW50cyBhdCBhIGJpbmFyeSB0byBydW4gaW5zdGVhZCBvZiB0aGUgaW5zdGFsbGVkIG9uZS4gKi9cbmV4cG9ydCBjb25zdCBCSU5BUllfRU5WID0gXCJIVE1MUFJFU1NfQklOQVJZXCJcblxuLyoqIEV2ZXJ5IHB1Ymxpc2hlZCBwbGF0Zm9ybSwga2V5ZWQgYnkgYCR7cHJvY2Vzcy5wbGF0Zm9ybX0tJHtwcm9jZXNzLmFyY2h9YC4gKi9cbmV4cG9ydCBjb25zdCBQTEFURk9STVM6IFJlY29yZDxzdHJpbmcsIFBsYXRmb3JtPiA9IHtcbiAgXCJsaW51eC14NjRcIjogY3JlYXRlUGxhdGZvcm0oXCJsaW51eC14NjRcIiwgXCJ4ODZfNjQtdW5rbm93bi1saW51eC1tdXNsXCIpLFxuICBcImxpbnV4LWFybTY0XCI6IGNyZWF0ZVBsYXRmb3JtKFwibGludXgtYXJtNjRcIiwgXCJhYXJjaDY0LXVua25vd24tbGludXgtbXVzbFwiKSxcbiAgXCJkYXJ3aW4teDY0XCI6IGNyZWF0ZVBsYXRmb3JtKFwiZGFyd2luLXg2NFwiLCBcIng4Nl82NC1hcHBsZS1kYXJ3aW5cIiksXG4gIFwiZGFyd2luLWFybTY0XCI6IGNyZWF0ZVBsYXRmb3JtKFwiZGFyd2luLWFybTY0XCIsIFwiYWFyY2g2NC1hcHBsZS1kYXJ3aW5cIiksXG4gIFwid2luMzIteDY0XCI6IGNyZWF0ZVBsYXRmb3JtKFwid2luMzIteDY0XCIsIFwieDg2XzY0LXBjLXdpbmRvd3MtbXN2Y1wiKSxcbiAgXCJ3aW4zMi1hcm02NFwiOiBjcmVhdGVQbGF0Zm9ybShcIndpbjMyLWFybTY0XCIsIFwiYWFyY2g2NC1wYy13aW5kb3dzLW1zdmNcIiksXG59XG5cbmZ1bmN0aW9uIGNyZWF0ZVBsYXRmb3JtKGtleTogc3RyaW5nLCB0YXJnZXQ6IHN0cmluZyk6IFBsYXRmb3JtIHtcbiAgY29uc3QgYmluYXJ5ID0ga2V5LnN0YXJ0c1dpdGgoXCJ3aW4zMlwiKSA/IFwiaHRtbHByZXNzLmV4ZVwiIDogXCJodG1scHJlc3NcIlxuICByZXR1cm4geyBwYWNrYWdlTmFtZTogYEBodG1scHJlc3MvJHtrZXl9YCwgdGFyZ2V0LCBiaW5hcnkgfVxufVxuIl19
package/package.json CHANGED
@@ -1,6 +1,40 @@
1
1
  {
2
2
  "name": "gethtmlpress",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Turn a folder of HTML pages into a site: one layout, one theme, live reload, made for agents",
5
+ "keywords": [
6
+ "agents",
7
+ "html",
8
+ "htmlpress",
9
+ "llm",
10
+ "static-site"
11
+ ],
12
+ "homepage": "https://htmlpress.dev",
13
+ "license": "MIT",
14
+ "author": "Evgeny Karev",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/datisthq/htmlpress.git",
18
+ "directory": "typescript"
19
+ },
20
+ "bin": {
21
+ "htmlpress": "./build/entrypoints/main.js"
22
+ },
23
+ "files": [
24
+ "build",
25
+ "skills"
26
+ ],
27
+ "type": "module",
28
+ "sideEffects": false,
29
+ "engines": {
30
+ "node": ">=20"
31
+ },
32
+ "optionalDependencies": {
33
+ "@htmlpress/linux-x64": "0.1.0",
34
+ "@htmlpress/linux-arm64": "0.1.0",
35
+ "@htmlpress/darwin-x64": "0.1.0",
36
+ "@htmlpress/darwin-arm64": "0.1.0",
37
+ "@htmlpress/win32-x64": "0.1.0",
38
+ "@htmlpress/win32-arm64": "0.1.0"
39
+ }
40
+ }
@@ -0,0 +1,151 @@
1
+ ---
2
+ name: htmlpress-authoring
3
+ description: Use when writing or editing pages in an htmlpress project — the page contract (title, order, head, metas), headings and the TOC, semantic HTML, the htmlpress-* components, code blocks, math, includes and checking the build.
4
+ ---
5
+
6
+ # Htmlpress Authoring
7
+
8
+ An htmlpress project is a folder of `.html` pages. Htmlpress wraps each in one layout with a
9
+ navigation and a theme, so a page carries content only: no `<nav>`, no site header, no styling.
10
+
11
+ ## When to use this skill
12
+
13
+ Invoke when the user asks to:
14
+
15
+ - Add, edit, move or reorder pages, or group them in the navigation.
16
+ - Use a callout, tabs, cards, steps or another component, or a code block, formula or diagram.
17
+ - Pull a shared partial or a source file into a page.
18
+
19
+ The config keys are in `htmlpress-configuration`; a different look in `htmlpress-customization`.
20
+
21
+ ## A page
22
+
23
+ ```html
24
+ <title>Getting started</title>
25
+ <meta name="description" content="Install and run it in a minute." />
26
+ <meta name="order" content="1" />
27
+
28
+ <h1>Getting started</h1>
29
+ <p>Plain semantic HTML.</p>
30
+ ```
31
+
32
+ - A full document (`<!doctype html>…<body>`) and a bare fragment are read the same way.
33
+ - `<title>` names the page in the navigation and the tab; without it the first `<h1>`, then the
34
+ file name. Give every page one `<title>` and one `<h1>`.
35
+ - `<meta name="order" content="N">` (an integer) sorts the navigation, lower first.
36
+ `index.html` always comes first; unordered pages follow by path, then negative orders
37
+ (`-1` pins a page last).
38
+ - Other `<head>` tags (`<link>`, `<style>`, `<script>`) are kept and added after the theme.
39
+ - The navigation nests pages by folder at any depth (`guides/cli/…` inside `guides/…`), each
40
+ group named by its `index.html`, whose title links to it.
41
+ - Pages are written to the same path, so link between them with relative hrefs
42
+ (`guides/build.html`). Images and other files are copied as-is; a relative `src`,
43
+ `srcset` or `poster` resolves from the source file, even when the page moves.
44
+ - A root `404.html` is the not-found page, kept out of the navigation; without one a built-in
45
+ is used.
46
+
47
+ ## Page metas
48
+
49
+ | Meta | Effect |
50
+ | -------------------------------------------- | ------------------------------------------------------------ |
51
+ | `description` | the page's summary for search, previews and `llms.txt` |
52
+ | `image` | its social preview image, relative to the file; needs `site` |
53
+ | `date` (`YYYY-MM-DD`), `author` (repeatable) | dates and signs it (a byline; none with `layout`) |
54
+ | `keywords` (`a, b`) | tags it (a blog post's tag pages) |
55
+ | `label` | a short name in the navigation |
56
+ | `icon` | a Lucide icon; top-level entries and folder index pages |
57
+ | `path` (`/start/`) | serves the page at another URL |
58
+ | `sidebar` (`false`) | built, not listed |
59
+ | `toc` (`false`) | no table of contents |
60
+ | `layout` (`<name>`) | another layout, from `htmlpress-customization` |
61
+ | `language` (`<code>`) | marks the page a translation |
62
+ | `source-url`, `source-action` (`view`) | the page's source link |
63
+
64
+ A file that cannot carry metas, such as a `README.md`, gets them from `patches` in the config.
65
+
66
+ ## Translations
67
+
68
+ With `languages` in the config, a translation is `page.<code>.html` beside `page.html`, or a
69
+ file with `<meta name="language" content="<code>">`. It pairs with the original by URL below the
70
+ language prefix, so a renamed one needs the same `<meta name="path">`. Untranslated pages stay
71
+ listed in every language with a badge and link to the original.
72
+
73
+ ## Headings
74
+
75
+ - `<h2>` to `<h4>` outside components make the page's table of contents; any `<h2>` to `<h6>`
76
+ without an `id` gets a slug of its text and an anchor link. Give a heading an `id` only when a link needs it fixed.
77
+ - A heading takes `data-toc="false"` (shown, not in the TOC) or `data-toc="only"` (in the TOC,
78
+ not shown); `<htmlpress-toc level="2">` (2–4, default 3) in a page renders its TOC inline.
79
+
80
+ ## Semantic HTML first
81
+
82
+ The theme styles the elements themselves: headings, `<p>`, lists, `<table>`, `<pre><code>`,
83
+ `<blockquote>`, `<details>`/`<summary>`, `<figure>`/`<figcaption>`, `<dl>`, `<kbd>`, `<hr>`.
84
+
85
+ - No inline `style`, no classes for looks, no utility CSS: every page should look like the same
86
+ site. A site-wide change is a token (`htmlpress-customization`).
87
+ - An image with `data-theme="light"` or `"dark"` shows in that theme only.
88
+ - `<abbr title>` and footnote references (`<sup><a href="#n1">` to an `<li id="n1">`) show a
89
+ hover hint; headings get a link on their own.
90
+ - Bare URLs and emails in prose become links and GitHub shortcodes (`:rocket:`) become emoji at
91
+ build time; text in links, code and `data-literal` elements stays as written.
92
+ - LaTeX: `$E = mc^2$` inline and `$$…$$` as a block (pandoc's rule keeps `$5 and $10` text; `\$`
93
+ is a dollar), or `<htmlpress-math display>…</htmlpress-math>`; rendered to MathML at build
94
+ time, and invalid LaTeX fails the build.
95
+ - `<htmlpress-include src="partial.html">` pastes in another file by path, relative to the page:
96
+ an `.html` body, rendered `.md`, or any other file as a titled code block that takes
97
+ `data-lines` and the other code block attributes. Exclude the partials folder in the config.
98
+
99
+ ## Code blocks
100
+
101
+ - Escape code inside `<pre><code>`: `&lt;` and `&amp;`. Name its language,
102
+ `<pre><code class="language-rust">`, to highlight it at build time; an inline
103
+ `<code class="language-js">` is highlighted too.
104
+ - `data-lines="2,4-5"` marks lines, `data-line-numbers` numbers them, `data-add`/`data-remove`
105
+ show a diff, `data-focus` dims the other lines, `data-error`/`data-warning` flag lines and
106
+ `data-words="a,b"` marks words.
107
+ - `<pre data-title="file.yaml">` adds a title bar with the language's logo;
108
+ `<pre data-collapse="10">` shows 10 lines with an Expand bar.
109
+ - `<pre><code class="language-ansi">` renders terminal color escapes (raw or `&#27;[31m`).
110
+ - Every block gets copy and wrap buttons. Tabs holding only code blocks join into one framed block.
111
+
112
+ ## Components
113
+
114
+ Only these; anything else is plain HTML. Put block content (`<p>`, `<h3>`, `<pre>`) inside a
115
+ component, not bare text.
116
+
117
+ | Element | Use |
118
+ | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------- |
119
+ | `<htmlpress-callout type="…" label="…">` | a note; `type` is `info` (default), `note`, `tip`, `success`, `warning`, `danger` |
120
+ | `<htmlpress-grid cols="2">` + `<htmlpress-card>` | cards in columns (`cols` 2–4, else responsive); `<h3><a>` links a card |
121
+ | `<htmlpress-tabs sync="…">` + `<section title>` | tabs, one per `<section>`; tabs sharing `sync` switch together |
122
+ | `<htmlpress-steps>` + `<ol>` | numbered steps, one per `<li>`, each led by an `<h3>` |
123
+ | `<htmlpress-badge type="…">` | an inline label; `type` as a callout's, `neutral`, `outline`, `ghost` or `link` |
124
+ | `<htmlpress-file-tree>` + nested `<ul>` | a file tree; an `<li>` holding a `<ul>` is a folder |
125
+ | `<htmlpress-table>` + `<table>` | a table sorted by a click on a `<thead>` header |
126
+ | `<htmlpress-zoom>` + `<img>` | an image that opens full screen on click |
127
+ | `<htmlpress-icon name="…">` | an inline Lucide icon; names at htmlpress.dev/authoring/rich-elements.html#icons |
128
+ | `<htmlpress-button type="…">` + `<a>` | a call-to-action link; `type` `secondary`/`outline`/`ghost`/`link`/`positive`/`warning`/`destructive`, `size` `sm`/`lg` |
129
+ | `<htmlpress-package-tabs>` + `<pre><code>` | one `npm`/`npx` command, built into npm, pnpm, yarn and bun tabs |
130
+ | `<htmlpress-terminal title="…">` + `<pre>` | terminal output: `<kbd>` command, `<samp>` output, `<ins>`/`<del>`/`<mark>` colours |
131
+ | `<htmlpress-youtube>` + `<a href>` | a YouTube video player for the linked video |
132
+ | `<htmlpress-soundcloud>` + `<a href>` | a SoundCloud player for the linked track |
133
+ | `<htmlpress-mermaid>` + `<pre>` | a Mermaid diagram from the source in `<pre>` (escape `<` and `&`) |
134
+
135
+ ## Verification
136
+
137
+ ```sh
138
+ htmlpress build <root> --json # {"output": "...", "pages": N, "files": N}; errors on stderr
139
+ htmlpress start <root> # http://localhost:8000 (or the next free port to 8009); --host for the network
140
+ htmlpress --llms # every command's input and output schema
141
+ ```
142
+
143
+ After editing, run `build --json` and confirm `pages` counts every page and the exit code is 0.
144
+ For a visual check, run `start` and open the page; look at it narrow as well as wide. Never edit
145
+ `.htmlpress/build/`: every build replaces it.
146
+
147
+ ## References
148
+
149
+ - Pages: https://htmlpress.dev/authoring/
150
+ - Components: https://htmlpress.dev/authoring/rich-elements.html
151
+ - Code blocks: https://htmlpress.dev/authoring/code-blocks.html
@@ -0,0 +1,124 @@
1
+ ---
2
+ name: htmlpress-configuration
3
+ description: Use when editing htmlpress.yaml — site metadata, base, include/exclude globs, code themes, sections (blog, changelog, custom), links, languages, versions, patches, head tags, agent skills, content signals and the edit link.
4
+ ---
5
+
6
+ # Htmlpress Configuration
7
+
8
+ `htmlpress.yaml` at the project root is optional; its keys follow Livemark's config. An unknown
9
+ key is an error, so a typo fails the build instead of being ignored.
10
+
11
+ ## When to use this skill
12
+
13
+ Invoke when the user asks to:
14
+
15
+ - Set the site's title, description, logo, favicon, banner or URL.
16
+ - Choose which files become pages, or leave some out.
17
+ - Add a blog, a changelog or another section, or links in the header or sidebar.
18
+ - Publish the site in several languages, or keep docs for older versions.
19
+ - Give a file metas it cannot carry, or publish a Markdown file as a page.
20
+ - Add tags to every page's `<head>`, publish skills or set `robots.txt` signals.
21
+
22
+ ## The config shape
23
+
24
+ ```yaml
25
+ site: https://example.com
26
+ base: /
27
+ title: Acme
28
+ description: Acme's docs.
29
+ logo: /logo.svg
30
+ favicon: /favicon.svg
31
+ banner: <a href="/blog/">We shipped 2.0</a>
32
+ include: [docs/**/*.html]
33
+ exclude: [docs/includes/**]
34
+ codeThemeLight: catppuccin-latte
35
+ codeThemeDark: catppuccin-mocha
36
+ edit: https://github.com/acme/acme/edit/main/
37
+ links:
38
+ - { title: GitHub, url: https://github.com/acme/acme, position: header, icon: github }
39
+ sections:
40
+ - { title: Blog, prefix: /blog/, type: blog }
41
+ patches:
42
+ - { file: README.md, article: { title: Overview, order: 1 } }
43
+ skills: [.skills/*/SKILL.md]
44
+ contentSignals: { search: true, aiInput: true, aiTrain: false }
45
+ head:
46
+ meta: [{ name: theme-color, content: "#0b5" }]
47
+ ```
48
+
49
+ - `site` — the canonical origin; with it a build writes `sitemap.xml` and absolute feed URLs.
50
+ - `base` — a sub-path such as `/repo/`. Root-relative URLs get it as a prefix, so write them
51
+ without it.
52
+ - `title`, `description`, `logo`, `favicon` (URLs) and `banner` (HTML above the header).
53
+ - `include` — globs of the `.html` files that become pages, default `**/*.html`. Only files under
54
+ a glob's base, its folders before the first wildcard, are read, and they are served without it:
55
+ `docs/**/*.html` serves `docs/guide.html` at `/guide.html`. Other files there are copied as-is.
56
+ - `exclude` — globs left out of the build: partials for includes, drafts.
57
+ - `codeThemeLight`, `codeThemeDark` — the code block themes, by Shiki theme name.
58
+ - `edit` — a URL prefix for an "Edit on GitHub" link.
59
+
60
+ ## Sections
61
+
62
+ Each has a `title` and a `prefix`; optional `icon`, `position`, `siteTitle`, `siteLink` and
63
+ `siteDescription`. The sidebar and pager then show only the open section's pages.
64
+
65
+ - `type: article` (the default) — the pages under the prefix.
66
+ - `type: blog` — dated posts (`date`, `author`, `keywords` metas) with tag pages and RSS.
67
+ - `type: changelog` plus `source` — a page per version of a Markdown changelog, or per
68
+ release of a GitHub repository URL (`GITHUB_TOKEN` when set, cached in `.htmlpress/cache/`); `version: true`
69
+ shows the latest version beside the title.
70
+ - `type: custom` plus `url` — a link to anywhere.
71
+
72
+ ## Links
73
+
74
+ Each has `title`, `url` and `position: header | sidebar`; optional `icon` and `prefix`, which
75
+ shows the link only under one folder.
76
+
77
+ ## Languages
78
+
79
+ `languages` lists each `code` and `label`, optional `locale`, `dir` (`ltr` or `rtl`), `flag` and
80
+ `messages` replacing UI strings. The first is the default; the others are served under
81
+ `/<code>/`. With `languages`, `title`, `description`, `banner` and link and section titles also
82
+ take a map by language code (`title: { en: Docs, es: Documentos }`). Translated pages are in
83
+ `htmlpress-authoring`.
84
+
85
+ ## Versions
86
+
87
+ There is no dedicated option. For a few versions on one branch, put each older version's pages
88
+ in a folder with a section of its own (`title: v1`, `prefix: /v1/`, `siteTitle: Acme v1`);
89
+ search stays site-wide, so results mix versions. For majors on their own branches, deploy each
90
+ branch as its own site (`base`, a `banner` linking to the latest) and link them with a `custom`
91
+ section.
92
+
93
+ ## Patches
94
+
95
+ Each patch is a `file` and an `article` of metas (`title`, `label`, `description`, `icon`,
96
+ `order`, `path`, `sidebar`, `toc`, `image`, `author`, `date`, `tags`, `sourceUrl`,
97
+ `sourceAction`), set without touching the file; a patched `.md` file such as `README.md` is
98
+ published as a page. A patched path outside the project, through a symlink or into a dot-folder is refused.
99
+
100
+ ## Agents and head
101
+
102
+ - `skills` — globs of `SKILL.md` files to publish under `.well-known/agent-skills/`.
103
+ - `contentSignals` — `search`, `aiInput`, `aiTrain` for `robots.txt`.
104
+ - `head` — `meta`, `links`, `scripts`: lists of attribute maps added to every page; a script's
105
+ `children` is its source.
106
+
107
+ ## Rules of thumb
108
+
109
+ - Change one key at a time and rebuild: the error names the key.
110
+ - Keep the config for site-wide facts; a page's own facts are its metas (`htmlpress-authoring`).
111
+ - `htmlpress start` rebuilds on a config change; no restart needed.
112
+
113
+ ## Verification
114
+
115
+ Run `htmlpress build <root> --json`: exit code 0 and the expected `pages` count. An unknown or
116
+ misspelt key fails here with its name.
117
+
118
+ ## References
119
+
120
+ - Configuration: https://htmlpress.dev/customization/configuration-file.html
121
+ - Sections: https://htmlpress.dev/customization/article-sections.html
122
+ - Translations: https://htmlpress.dev/customization/translations.html
123
+ - Versioning: https://htmlpress.dev/customization/versioning.html
124
+ - Patches: https://htmlpress.dev/customization/article-patches.html
@@ -0,0 +1,135 @@
1
+ ---
2
+ name: htmlpress-customization
3
+ description: Use when changing an htmlpress site's look or chrome — overriding --htmlpress-* tokens, escaping the layout, styles or a component into .htmlpress/ with `htmlpress escape`, adding layouts and project components.
4
+ ---
5
+
6
+ # Htmlpress Customization
7
+
8
+ Htmlpress ships a layout, a theme and a library of components, all compiled into the binary.
9
+ A file under `.htmlpress/` at a built-in's path replaces it; a new name adds one of your own.
10
+
11
+ ## When to use this skill
12
+
13
+ Invoke when the user asks to:
14
+
15
+ - Rebrand: colours, fonts, widths, radius.
16
+ - Change the header, sidebar, footer or another part of the chrome.
17
+ - Restyle a component, or add a block the built-in components do not have.
18
+ - Give some pages a different layout, such as a landing page without the sidebar
19
+ (`htmlpress-landing` covers what goes on one).
20
+
21
+ Do not escape for content: a page's own needs are semantic HTML and components
22
+ (`htmlpress-authoring`).
23
+
24
+ ## Tokens first
25
+
26
+ Most looks are a token. Override it in `.htmlpress/styles/tokens.css`, or in one page's own
27
+ `<style>` for that page only:
28
+
29
+ ```css
30
+ :root {
31
+ --htmlpress-accent: oklch(0.55 0.24 27);
32
+ }
33
+ ```
34
+
35
+ `--htmlpress-accent`, `-accent-text`, `-font`, `-mono`, `-bg`, `-surface`, `-text`, `-muted`,
36
+ `-prose`, `-prose-strong`, `-prose-marker`, `-border`, `-shadow`, `-radius`, `-width`,
37
+ `-nav-width`, `-banner`, `-banner-text`, `-highlight`, `-highlight-text` (search matches on
38
+ the page a result opened), and the
39
+ callout and badge tones `-info`, `-success`, `-warning`, `-danger`.
40
+
41
+ ## Escaping
42
+
43
+ ```sh
44
+ htmlpress escape # list every file, marking the escaped ones
45
+ htmlpress escape htmlpress-tabs # a component's .css and .js
46
+ htmlpress escape layout.html styles/tokens.css
47
+ htmlpress escape htmlpress-tabs -r docs # in another project folder
48
+ ```
49
+
50
+ `escape` copies a default to start from and never overwrites a file you already have. Deleting
51
+ an escape restores the default. An escaped copy keeps the code it was copied from, so after an
52
+ upgrade it misses the new defaults: escape only what you change.
53
+
54
+ | Path under `.htmlpress/` | Replaces |
55
+ | ------------------------------------------------ | ----------------------------------------------------------------- |
56
+ | `layout.html` | the page around the content |
57
+ | `layouts/<name>.html` | a layout of your own, picked by `<meta name="layout">` |
58
+ | `styles/tokens.css`, `layout.css`, `content.css` | the global theme: tokens, page globals, content elements |
59
+ | `favicon.svg` | the icon linked when the config sets neither `favicon` nor `logo` |
60
+ | `components/<name>/<name>.css`, `.js` | one component, `<htmlpress-<name>>` without its prefix |
61
+
62
+ ## Layouts
63
+
64
+ `layout.html` is plain HTML: htmlpress fills its `<head>` and replaces `<htmlpress-content>`,
65
+ `<htmlpress-brand>`, `<htmlpress-banner>`, `<htmlpress-nav>`, `<htmlpress-links>`,
66
+ `<htmlpress-breadcrumbs>`, `<htmlpress-toc>`, `<htmlpress-pager>`, `<htmlpress-edit>`,
67
+ `<htmlpress-toolbar>`, `<htmlpress-footer>`, `<htmlpress-language>` (the language picker) and
68
+ `<htmlpress-skip>` at build time, every string in the page's language. The interactive ones,
69
+ `<htmlpress-nav-toggle>`, `<htmlpress-search>`, `<htmlpress-theme-toggle>`, `<htmlpress-toc-bar>`
70
+ (the phone's contents bar and sheet) and `<htmlpress-back-to-top>`, run in the browser; the first three get their button at build time,
71
+ so the header is whole on its first frame. A head script sets `data-scripted` on `<html>`:
72
+ without it those buttons stay hidden, so style anything that needs scripts under
73
+ `:root[data-scripted]`. An element with nothing to show is removed.
74
+
75
+ Pages crossfade only their content: `<htmlpress-header>` and `<htmlpress-sidebar>` carry the
76
+ view transition names `htmlpress-header` and `htmlpress-sidebar`, and a hovered link's page is
77
+ prerendered. An escape of either component's `.css` keeps its `view-transition-name`, or it
78
+ crossfades with the content.
79
+
80
+ The frame is elements too, never classes: `<htmlpress-shell>`, `-sidebar`, `-main`, `-header`,
81
+ `-page`, `-aside`, `-skip`, each a component whose `.css` can be escaped.
82
+
83
+ A page with `<meta name="layout" content="landing">` takes `layouts/landing.html` instead. It
84
+ starts bare: only the layout elements you put in it are drawn. A missing layout fails the build.
85
+
86
+ ## Project components
87
+
88
+ A folder under `components/` with a new name adds `<htmlpress-<name>>`, each file named like
89
+ the folder:
90
+
91
+ ```html
92
+ <!-- .htmlpress/components/credits/credits.html -->
93
+ <footer><p>Built by my team · 2026</p></footer>
94
+ ```
95
+
96
+ ```css
97
+ /* .htmlpress/components/credits/credits.css */
98
+ @scope (htmlpress-credits) {
99
+ :scope {
100
+ display: block;
101
+ }
102
+ p {
103
+ color: var(--htmlpress-muted);
104
+ }
105
+ }
106
+ ```
107
+
108
+ - The `.html` fills every such tag in the layouts and pages at build time; the tag stays, so its
109
+ `.css` scopes to it. A custom element is inline until its CSS says otherwise.
110
+ - Its `.css` and `.js` load only where the tag appears. A name is lowercase letters, digits and
111
+ hyphens.
112
+ - A layout or a component's `.html` may hold any built-in component, but not another project
113
+ component's tag: it is pasted in once, never rewritten again.
114
+ - The markup inside a layout element (`nav`, `toc`, `pager`, …) is built from the site; a
115
+ `components/brand/brand.html` replaces it with static HTML, and the built-in `.css` still
116
+ applies to the tag.
117
+
118
+ ## Rules of thumb
119
+
120
+ - A misspelt built-in name (`calout/`) adds a component rather than replacing one; a file
121
+ directly in `components/` fails the build. Check `htmlpress escape` marks the file escaped.
122
+ - To restyle a component from an outer one, beat its `:scope`: write `:scope htmlpress-header`,
123
+ not a bare `htmlpress-header`, which loses on specificity.
124
+ - Use tokens inside your CSS (`var(--htmlpress-muted)`) so dark mode keeps working.
125
+
126
+ ## Verification
127
+
128
+ Run `htmlpress build <root> --json` (exit code 0), then `htmlpress start <root>` and look at
129
+ the change in light and dark, wide and phone width. `start` picks up a new or deleted escape
130
+ at once.
131
+
132
+ ## References
133
+
134
+ - Overriding: https://htmlpress.dev/customization/overriding-escaping.html
135
+ - Layouts: https://htmlpress.dev/customization/custom-routes.html
@@ -0,0 +1,72 @@
1
+ ---
2
+ name: htmlpress-deployment
3
+ description: Use when publishing an htmlpress site — building into .htmlpress/build/, setting site and base, and wiring Cloudflare, GitHub Pages, Vercel, Netlify or any static host, by hand or from CI.
4
+ ---
5
+
6
+ # Htmlpress Deployment
7
+
8
+ `htmlpress build` writes a fully static site; every host that serves a directory of files can
9
+ serve it. There is no client-side routing, so no host needs an SPA fallback.
10
+
11
+ ## When to use this skill
12
+
13
+ Invoke when the user asks to:
14
+
15
+ - Publish the site, or set up a host or a CI deploy.
16
+ - Serve it under a sub-path such as a GitHub Pages project site.
17
+ - Fix a deploy that 404s, loses its styles or misses `sitemap.xml`.
18
+
19
+ ## The build
20
+
21
+ ```sh
22
+ htmlpress build # or `npx gethtmlpress build` in CI, without installing it
23
+ htmlpress preview # serves the production build locally, the way a host will
24
+ htmlpress clear # removes .htmlpress/build
25
+ ```
26
+
27
+ The output is `.htmlpress/build/`: an `.html` per page at its source's path, `404.html`,
28
+ `robots.txt`, `_headers`, a Markdown copy of each page and `llms.txt` for agents, the skills
29
+ under `.well-known/agent-skills/`, the theme under `_htmlpress/`, and every other project file.
30
+ With `site` set it adds `sitemap.xml`. Never edit the output: every build replaces it.
31
+
32
+ ## Config that affects deployment
33
+
34
+ - `site` — the final origin (`https://docs.example.com`): `sitemap.xml`, canonical URLs and
35
+ absolute social tags need it.
36
+ - `base` — only for a sub-path (`/my-docs/`). Write links without it; the build prefixes every
37
+ root-relative URL, and `start` and `preview` serve under it too. A custom domain needs no
38
+ `base`.
39
+
40
+ ## Hosts
41
+
42
+ | Host | Setup |
43
+ | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
44
+ | Cloudflare Workers | `wrangler.jsonc`: `assets.directory: ".htmlpress/build"`, `html_handling: "none"`, `not_found_handling: "404-page"`; `npx wrangler deploy` |
45
+ | GitHub Pages | `site: https://<user>.github.io`, `base: /<repo>/`; `npx gh-pages -d .htmlpress/build --nojekyll --dotfiles`, or the Pages actions uploading `.htmlpress/build` |
46
+ | Vercel | `vercel.json`: `"framework": null`, `"buildCommand": "npx gethtmlpress build"`, `"outputDirectory": ".htmlpress/build"` |
47
+ | Netlify | `netlify.toml`: `[build] command = "npx gethtmlpress build"`, `publish = ".htmlpress/build"` |
48
+ | nginx | `try_files $uri $uri/ =404;` and `error_page 404 /404.html;` |
49
+ | Caddy | `file_server` plus `handle_errors { rewrite * /404.html; file_server }` |
50
+ | S3 + CloudFront | index `index.html`, error `404.html`, a 404 custom error response to `/404.html` |
51
+
52
+ ## Rules of thumb
53
+
54
+ - Point the host's not-found page at `404.html`, so unknown paths keep the site's layout.
55
+ - Keep `html_handling: "none"` on Cloudflare: its default redirects `/guide.html` to `/guide`,
56
+ away from the URLs htmlpress links to.
57
+ - Keep `--nojekyll` and `--dotfiles` on a GitHub Pages branch deploy: Jekyll drops the
58
+ `_htmlpress/` theme, and without dot-files `.well-known/` is lost.
59
+ - Files under `_htmlpress/` keep their names between builds: cache them briefly or invalidate
60
+ them on each release.
61
+ - A project's dot-files are never copied: keep an `.htaccess` on the server.
62
+
63
+ ## Verification
64
+
65
+ Run `htmlpress build --json` and `htmlpress preview`, then after the deploy open the home page,
66
+ a nested page, an unknown path (the site's 404) and `/robots.txt`. Under a `base`, check that
67
+ styles load and links keep the prefix.
68
+
69
+ ## References
70
+
71
+ - Deployment: https://htmlpress.dev/deployment/
72
+ - Static hosting: https://htmlpress.dev/deployment/static-hosting.html
@@ -0,0 +1,111 @@
1
+ ---
2
+ name: htmlpress-landing
3
+ description: Use when designing or rewriting an htmlpress project's landing page — a layout of its own, hero, sections, screenshots and calls to action as project components, taking htmlpress.dev's own landing as the reference.
4
+ ---
5
+
6
+ # Htmlpress Landing
7
+
8
+ Guidance for designing the page at `/` of an htmlpress project. The mechanics of a layout and a
9
+ project component are in `htmlpress-customization`; this skill is about what goes on the page.
10
+
11
+ ## When to use this skill
12
+
13
+ Invoke when the user asks to:
14
+
15
+ - Build a landing, home or marketing page for the site, or redesign the existing one.
16
+ - Add a hero, feature grid, screenshot carousel or call-to-action section.
17
+ - Make the landing look as polished as htmlpress.dev.
18
+
19
+ ## Start from the reference
20
+
21
+ htmlpress.dev's landing is itself an htmlpress page with its own layout and a set of project
22
+ components. Read it before writing anything, see it live, and borrow its structure:
23
+
24
+ - Live: https://htmlpress.dev/
25
+ - Page: https://github.com/datisthq/htmlpress/blob/main/rust/docs/index.html
26
+ - Layout and components: https://github.com/datisthq/htmlpress/tree/main/.htmlpress
27
+
28
+ None of it is in the packages, so fetch it from GitHub. Take the patterns, not the content:
29
+ rewrite every heading and line of copy for the project, and use the project's own screenshots
30
+ and links. Shipping htmlpress' copy, screenshots or Datist credit on someone else's site is a bug.
31
+
32
+ ## Skeleton
33
+
34
+ ```html
35
+ <!-- index.html -->
36
+ <title>Home</title>
37
+ <meta name="description" content="What the project does, in one line." />
38
+ <meta name="layout" content="landing" />
39
+ <meta name="sidebar" content="false" />
40
+
41
+ <htmlpress-landing-hero>…</htmlpress-landing-hero>
42
+ <htmlpress-landing-section>…</htmlpress-landing-section>
43
+ <htmlpress-landing-cta>…</htmlpress-landing-cta>
44
+ ```
45
+
46
+ ```html
47
+ <!-- .htmlpress/layouts/landing.html -->
48
+ <!doctype html>
49
+ <html lang="en">
50
+ <head></head>
51
+ <body>
52
+ <htmlpress-skip><a href="#content">Skip to content</a></htmlpress-skip>
53
+ <htmlpress-landing-page>
54
+ <htmlpress-banner></htmlpress-banner>
55
+ <htmlpress-header role="banner">
56
+ <htmlpress-brand></htmlpress-brand>
57
+ <htmlpress-links></htmlpress-links>
58
+ <htmlpress-search></htmlpress-search>
59
+ <htmlpress-theme-toggle></htmlpress-theme-toggle>
60
+ </htmlpress-header>
61
+ <main id="content"><htmlpress-content></htmlpress-content></main>
62
+ <htmlpress-landing-footer></htmlpress-landing-footer>
63
+ </htmlpress-landing-page>
64
+ <htmlpress-back-to-top></htmlpress-back-to-top>
65
+ </body>
66
+ </html>
67
+ ```
68
+
69
+ The reference runs hero → a differentiator ("Stays out of your way") → a feature grid → an
70
+ audience section (agents) → a final call to action → a credit footer. Pick the sections the
71
+ project has something real to say in; three strong ones beat seven thin ones.
72
+
73
+ ## Patterns from the reference
74
+
75
+ - **One component per block** — `landing-hero`, `-section`, `-features`, `-points`, `-cta`,
76
+ `-actions`, `-carousel`, `-window`, `-code`, `-backdrop`, `-footer`, `-page`, each a folder
77
+ under `.htmlpress/components/` with a `.css` scoped to its tag, and `.js` or `.html` only
78
+ where needed. The page holds semantic HTML inside them: `<section>`, `<header>`, `<hgroup>`,
79
+ `<h2>`, `<ul>` of `<li>` cards. No classes.
80
+ - **Section shell** — `<htmlpress-landing-section><section><header><h2>` plus a lede, then the
81
+ body; a two-column section pairs a point list with a visual (`landing-points` beside
82
+ `landing-window`).
83
+ - **Hero** — a short eyebrow `<p>` in an `<hgroup>` with the `<h1>`, a lede, then
84
+ `landing-actions` with two links: the docs first, the source second. A decorative
85
+ `landing-backdrop` takes `aria-hidden="true"`.
86
+ - **Show the product** — real screenshots, not stock art, each shipped light and dark as two
87
+ `<img>` toggled by the theme with an attribute the component's CSS reads; set `width` and
88
+ `height` so nothing shifts. `landing-carousel` turns `<section title>` slides into tabs.
89
+ - **Icons** — inline `<svg aria-hidden="true">` with `currentColor` strokes, so they follow the
90
+ theme.
91
+ - **Colour** — only `--htmlpress-*` tokens and `color-mix(in oklab, …)` of them, so the page
92
+ rebrands and goes dark with the rest of the site.
93
+
94
+ ## Rules of thumb
95
+
96
+ - Links are root-relative (`/introduction.html`); `base` is added at build time.
97
+ - Keep the landing out of the sidebar (`sidebar` false) but give it a real `<title>` and
98
+ `description`: it is the site's social preview.
99
+ - Every component must read well with its JS off: the slides are already in the HTML.
100
+ - Check phone width first; a two-column section must fall back to one.
101
+
102
+ ## Verification
103
+
104
+ Run `htmlpress build <root> --json`, then `htmlpress start <root>` and look at `/` in light and
105
+ dark, wide and at phone width. Tab through it: the skip link, the actions and the carousel must
106
+ be reachable by keyboard.
107
+
108
+ ## References
109
+
110
+ - Layouts: https://htmlpress.dev/customization/custom-routes.html
111
+ - Overriding: https://htmlpress.dev/customization/overriding-escaping.html