@call-me-sensei/toonlab 0.1.1 → 0.3.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.
Files changed (213) hide show
  1. package/AGENTS.md +254 -0
  2. package/ATTRIBUTION.md +41 -3
  3. package/README.md +300 -27
  4. package/docs/characters.md +144 -0
  5. package/docs/debug-panel.md +126 -0
  6. package/docs/docs.css +589 -0
  7. package/docs/environment.md +186 -0
  8. package/docs/getting-started.md +180 -0
  9. package/docs/index.html +14 -0
  10. package/docs/lab-architecture.md +100 -0
  11. package/docs/lighting.md +825 -0
  12. package/docs/main.jsx +739 -0
  13. package/docs/mcp.md +97 -0
  14. package/docs/post-processing.md +98 -0
  15. package/docs/settings-reference.md +1878 -0
  16. package/docs/shader-constants.md +77 -0
  17. package/docs/sky.md +182 -0
  18. package/docs/style-labs.md +309 -0
  19. package/docs/texture-lab.md +135 -0
  20. package/docs/toon-shading.md +183 -0
  21. package/docs/tsl-conventions.md +167 -0
  22. package/docs/vegetation-sky.md +275 -0
  23. package/docs/water.md +430 -0
  24. package/docs/weather.md +200 -0
  25. package/docs/world-scale.md +111 -0
  26. package/mcp/server.mjs +610 -0
  27. package/mcp/style-lab-tools.mjs +371 -0
  28. package/mcp/vite-plugin.mjs +174 -0
  29. package/mcp/workspace.mjs +397 -0
  30. package/package.json +66 -6
  31. package/src/ambientfx/INTEGRATION.md +164 -0
  32. package/src/ambientfx/ambientFxPresets.js +83 -0
  33. package/src/ambientfx/ambientFxSettings.js +368 -0
  34. package/src/ambientfx/emitters.js +169 -0
  35. package/src/ambientfx/index.js +5 -0
  36. package/src/ambientfx/particleBackbone.js +493 -0
  37. package/src/ambientfx/stylizedAmbientFx.js +450 -0
  38. package/src/assetlib/ambientcg.js +117 -0
  39. package/src/assetlib/assetRef.js +91 -0
  40. package/src/assetlib/importedEntry.js +40 -0
  41. package/src/assetlib/index.js +23 -0
  42. package/src/assetlib/kaykit.js +192 -0
  43. package/src/assetlib/kaykitStaticIndex.js +700 -0
  44. package/src/assetlib/loadImported.js +143 -0
  45. package/src/assetlib/opensource3d.js +113 -0
  46. package/src/assetlib/polyhaven.js +182 -0
  47. package/src/assetlib/polypizza.js +115 -0
  48. package/src/assetlib/smithsonian.js +214 -0
  49. package/src/assetlib/sources.js +279 -0
  50. package/src/assetlib/zip.js +58 -0
  51. package/src/biome/biomeGenerator.js +385 -0
  52. package/src/biome/biomeRuntime.js +299 -0
  53. package/src/biome/index.js +2 -0
  54. package/src/buildinggen/buildingAsset.js +44 -0
  55. package/src/buildinggen/buildingGrammar.js +311 -0
  56. package/src/buildinggen/buildingMesh.js +451 -0
  57. package/src/buildinggen/buildingPresets.js +46 -0
  58. package/src/buildinggen/buildingRecipe.js +100 -0
  59. package/src/buildinggen/buildingSettings.js +238 -0
  60. package/src/buildinggen/index.js +6 -0
  61. package/src/camera/cameraDirector.js +157 -0
  62. package/src/camera/cameraGenerator.js +367 -0
  63. package/src/camera/cameraRig.js +570 -0
  64. package/src/camera/cameraSettings.js +236 -0
  65. package/src/camera/index.js +7 -0
  66. package/src/catalog/builtinEntries.js +245 -0
  67. package/src/catalog/catalog.js +210 -0
  68. package/src/catalog/index.js +3 -0
  69. package/src/catalog/manifest.js +84 -0
  70. package/src/core/generation.js +529 -0
  71. package/src/debrisgen/debrisPresets.js +7 -0
  72. package/src/environment/environmentPresets.js +19 -0
  73. package/src/environment/environmentRigs.js +21 -1
  74. package/src/environment/environmentSettings.js +14 -0
  75. package/src/environment/environmentSunShadowPass.js +8 -0
  76. package/src/environment/environmentTextureResolver.js +3 -0
  77. package/src/environment/index.js +1 -0
  78. package/src/fauna/INTEGRATION.md +174 -0
  79. package/src/fauna/boids.js +861 -0
  80. package/src/fauna/faunaBodies.js +492 -0
  81. package/src/fauna/faunaPresets.js +52 -0
  82. package/src/fauna/faunaSettings.js +525 -0
  83. package/src/fauna/index.js +5 -0
  84. package/src/fauna/stylizedFauna.js +395 -0
  85. package/src/game-feel/gameFeelGenerator.js +402 -0
  86. package/src/game-feel/gameFeelRuntime.js +549 -0
  87. package/src/game-feel/index.js +2 -0
  88. package/src/index.js +22 -4
  89. package/src/lighting/colorIntensity.js +177 -0
  90. package/src/lighting/index.js +161 -0
  91. package/src/lighting/lightDescriptors.js +249 -0
  92. package/src/lighting/lightingCapabilities.js +79 -0
  93. package/src/lighting/lightingDocuments.js +247 -0
  94. package/src/lighting/lightingFixtures.js +446 -0
  95. package/src/lighting/lightingGenerator.js +449 -0
  96. package/src/lighting/lightingPresets.js +319 -0
  97. package/src/lighting/lightingRuntime.js +723 -0
  98. package/src/lighting/lightingStyle.js +386 -0
  99. package/src/lighting/lightingSystem.js +774 -0
  100. package/src/lighting/unrealExport.js +186 -0
  101. package/src/lighting/utils.js +87 -0
  102. package/src/motion/index.js +5 -0
  103. package/src/motion/motionClip.js +441 -0
  104. package/src/motion/motionController.js +628 -0
  105. package/src/motion/motionDocuments.js +225 -0
  106. package/src/motion/motionGraph.js +307 -0
  107. package/src/motion/motionSettings.js +222 -0
  108. package/src/pathgen/index.js +7 -0
  109. package/src/pathgen/pathBridge.js +232 -0
  110. package/src/pathgen/pathPresets.js +35 -0
  111. package/src/pathgen/pathRibbon.js +410 -0
  112. package/src/pathgen/pathRouter.js +380 -0
  113. package/src/pathgen/pathSettings.js +335 -0
  114. package/src/pathgen/pathTextures.js +123 -0
  115. package/src/pathgen/stylizedPaths.js +453 -0
  116. package/src/post/index.js +1 -0
  117. package/src/post/postGenerator.js +177 -0
  118. package/src/post/postProcessing.js +69 -0
  119. package/src/propgen/generatorsWave1.js +379 -0
  120. package/src/propgen/generatorsWave2.js +462 -0
  121. package/src/propgen/index.js +5 -0
  122. package/src/propgen/propAsset.js +323 -0
  123. package/src/propgen/propParts.js +170 -0
  124. package/src/propgen/propPlacement.js +459 -0
  125. package/src/propgen/propPresets.js +82 -0
  126. package/src/propgen/propSettings.js +395 -0
  127. package/src/rockgen/rockgenPresets.js +8 -0
  128. package/src/rockgen/rockgenSettings.js +47 -0
  129. package/src/shaders-tsl/chunks/projected-water-caustics.js +242 -0
  130. package/src/shaders-tsl/chunks/vegetation-style.js +360 -0
  131. package/src/shaders-tsl/chunks/water-shore-state.js +31 -0
  132. package/src/shaders-tsl/chunks/water-waves.js +90 -11
  133. package/src/shaders-tsl/environment.js +75 -1
  134. package/src/shaders-tsl/flower.js +279 -30
  135. package/src/shaders-tsl/grass.js +60 -33
  136. package/src/shaders-tsl/sky.js +125 -31
  137. package/src/shaders-tsl/tree-leaf.js +61 -25
  138. package/src/shaders-tsl/water-breaker.js +7 -4
  139. package/src/shaders-tsl/water-shore-state-simulation.js +523 -0
  140. package/src/shaders-tsl/water.js +488 -45
  141. package/src/shaders-tsl/woody-surface.js +154 -0
  142. package/src/sky/sceneOverrideLayers.js +10 -0
  143. package/src/sky/skyQuality.js +26 -0
  144. package/src/sky/stylizedSky.js +776 -20
  145. package/src/soundscape/index.js +4 -0
  146. package/src/soundscape/soundscapeGenerator.js +179 -0
  147. package/src/soundscape/soundscapeRuntime.js +806 -0
  148. package/src/soundscape/soundscapeSettings.js +292 -0
  149. package/src/styles/index.js +13 -0
  150. package/src/styles/styleBundle.js +325 -0
  151. package/src/stylizedTerrain.js +631 -0
  152. package/src/stylizedWorld.js +903 -0
  153. package/src/texgen/evaluateTexture.js +675 -0
  154. package/src/texgen/index.js +60 -0
  155. package/src/texgen/noise2.js +210 -0
  156. package/src/texgen/textureAi.js +436 -0
  157. package/src/texgen/textureGenerators.js +516 -0
  158. package/src/texgen/texturePresets.js +490 -0
  159. package/src/texgen/textureSettings.js +342 -0
  160. package/src/texgen/textureThree.js +59 -0
  161. package/src/vegetation/flowerSpecies.js +15 -3
  162. package/src/vegetation/grassPalettes.js +153 -0
  163. package/src/vegetation/index.js +8 -0
  164. package/src/vegetation/scatter.js +297 -0
  165. package/src/vegetation/stylizedBush.js +2 -0
  166. package/src/vegetation/stylizedFlower.js +82 -0
  167. package/src/vegetation/stylizedFlowers.js +96 -8
  168. package/src/vegetation/stylizedForest.js +476 -0
  169. package/src/vegetation/stylizedGrass.js +331 -48
  170. package/src/vegetation/stylizedTree.js +109 -4
  171. package/src/vegetation/stylizedTreeFoliage.js +13 -3
  172. package/src/vegetation/vegetationShaders.js +1110 -0
  173. package/src/vfxgen/INTEGRATION.md +145 -0
  174. package/src/vfxgen/core/burstBackbone.js +380 -0
  175. package/src/vfxgen/core/projectileCore.js +92 -0
  176. package/src/vfxgen/core/spriteShapes.js +98 -0
  177. package/src/vfxgen/core/trailRibbon.js +272 -0
  178. package/src/vfxgen/core/vfxRandom.js +29 -0
  179. package/src/vfxgen/effects/emitHelpers.js +37 -0
  180. package/src/vfxgen/effects/magicEffects.js +162 -0
  181. package/src/vfxgen/effects/movementEffects.js +87 -0
  182. package/src/vfxgen/effects/weaponEffects.js +118 -0
  183. package/src/vfxgen/index.js +18 -0
  184. package/src/vfxgen/moves/moveController.js +146 -0
  185. package/src/vfxgen/moves/moveLibrary.js +335 -0
  186. package/src/vfxgen/vfxPresets.js +98 -0
  187. package/src/vfxgen/vfxSettings.js +384 -0
  188. package/src/vfxgen/vfxSystem.js +449 -0
  189. package/src/vfxgen/weapons/stylizedWeapons.js +137 -0
  190. package/src/villagegen/index.js +4 -0
  191. package/src/villagegen/stylizedVillage.js +490 -0
  192. package/src/villagegen/villageArchetypes.js +160 -0
  193. package/src/villagegen/villageNames.js +40 -0
  194. package/src/villagegen/villageSites.js +105 -0
  195. package/src/water/sceneOverrideLayers.js +23 -0
  196. package/src/water/water.js +5 -0
  197. package/src/water/waterBreakerSystem.js +15 -1
  198. package/src/water/waterCurrentField.js +447 -0
  199. package/src/water/waterMaterial.js +12 -0
  200. package/src/water/waterNearshorePhase.js +320 -0
  201. package/src/water/waterScenePasses.js +86 -29
  202. package/src/water/waterSettings.js +335 -13
  203. package/src/water/waterShoreMaterial.js +322 -0
  204. package/src/water/waterShoreStateField.js +605 -0
  205. package/src/water/waterSurface.js +824 -28
  206. package/src/weather/index.js +6 -0
  207. package/src/weather/weatherPrecipitation.js +221 -0
  208. package/src/weather/weatherPresets.js +258 -0
  209. package/src/weather/weatherSettings.js +269 -0
  210. package/src/weather/weatherSystem.js +871 -0
  211. package/src/worldCollision.js +94 -0
  212. package/src/worldMinimap.js +214 -0
  213. package/src/worldPresets.js +125 -0
@@ -0,0 +1,126 @@
1
+ # Debug panel
2
+
3
+ `@call-me-sensei/toonlab/debug` is an optional, DOM-dependent tuning GUI: it turns any
4
+ settings module's group/field schema into live controls. One call gives you
5
+ the same panel the labs use — ship it behind a debug flag, or not at all
6
+ (nothing else imports it).
7
+
8
+ The labs now expose one TSL renderer stack: native WebGPU by default and
9
+ `?renderer=webgl` for the WebGL2 fallback. The panel writes the same settings
10
+ surface on both backends.
11
+
12
+ ## createSettingsPanel
13
+
14
+ ```js
15
+ import { createSettingsPanel } from '@call-me-sensei/toonlab/debug';
16
+ import { readFieldValueFromSettings } from '@call-me-sensei/toonlab/debug';
17
+ import {
18
+ TOON_SETTING_GROUPS,
19
+ TOON_SETTING_FIELD_SCHEMA,
20
+ applyToonSettingsToMaterial,
21
+ } from '@call-me-sensei/toonlab/toon';
22
+
23
+ const panel = createSettingsPanel({
24
+ container: document.getElementById('toonSettingGroups'),
25
+ groups: TOON_SETTING_GROUPS,
26
+ fieldSchema: TOON_SETTING_FIELD_SCHEMA,
27
+ getValue: (field) => readFieldValueFromSettings(settings, field),
28
+ onChange: (field, value) => {
29
+ settings[field.group][field.key] = value;
30
+ applyToonSettingsToMaterial(characterRoot, settings);
31
+ },
32
+ });
33
+
34
+ panel.refresh(); // re-pull every control value via getValue (e.g. after a preset switch)
35
+ ```
36
+
37
+ (Inside this repo the labs import from `../../src/debug/...`.)
38
+
39
+ The panel renders one collapsible `<details>` group per schema group, with a
40
+ typed control per field — checkbox for `boolean`, `<select>` for `select`
41
+ (using the schema's `options`/`optionLabels`), color input for `color`,
42
+ range slider for `number` (using the schema's `range`), text input
43
+ otherwise — each with a label, tooltip description, and live `<output>`
44
+ readout.
45
+
46
+ The host owns the settings state: the panel only reads through `getValue`
47
+ and reports edits through `onChange`. It never mutates settings itself,
48
+ which is what makes it schema-generic.
49
+
50
+ ### Options
51
+
52
+ Beyond the required five, `createSettingsPanel` accepts:
53
+
54
+ - `fieldFilter(field)` — hide fields (e.g. non-serializable texture slots).
55
+ - `isDisabled(field)` — gray controls out (re-evaluated on `refresh()`).
56
+ - `formatValue(value, field)` — custom `<output>` formatting.
57
+ - `isGroupOpen(group)` — which groups start expanded.
58
+ - `prepend` — DOM nodes to insert before the groups (preset pickers, etc.).
59
+ - `dataAttribute`, `idPrefix`, `rowClassName`, `groupClassName`,
60
+ `fieldsClassName` — styling/data hooks.
61
+
62
+ ### It works with every schema
63
+
64
+ Any module following the groups + field-schema convention plugs in — this is
65
+ the full list (see the generated
66
+ [settings reference](settings-reference.md) for their contents):
67
+
68
+ | Module | groups / fieldSchema |
69
+ |---|---|
70
+ | `@call-me-sensei/toonlab/toon` | `TOON_SETTING_GROUPS` / `TOON_SETTING_FIELD_SCHEMA` |
71
+ | `@call-me-sensei/toonlab/environment` | `ENVIRONMENT_SETTING_GROUPS` / `ENVIRONMENT_SETTING_FIELD_SCHEMA` |
72
+ | `@call-me-sensei/toonlab/water` | `WATER_SETTING_GROUPS` / `WATER_SETTING_FIELD_SCHEMA_BY_GROUP` |
73
+ | `@call-me-sensei/toonlab/post` | `POST_PROCESSING_SETTING_GROUPS` / `POST_PROCESSING_SETTING_FIELD_SCHEMA` |
74
+ | `@call-me-sensei/toonlab/vegetation` (grass) | `GRASS_SETTING_GROUPS` / `GRASS_SETTING_FIELD_SCHEMA` |
75
+ | `@call-me-sensei/toonlab/vegetation` (flowers) | `FLOWER_SETTING_GROUPS` / `FLOWER_SETTING_FIELD_SCHEMA` |
76
+ | `@call-me-sensei/toonlab/vegetation` (trees) | `STYLIZED_TREE_SETTING_GROUPS` / `STYLIZED_TREE_SETTING_FIELD_SCHEMA` |
77
+ | `@call-me-sensei/toonlab/sky` | `SKY_SETTING_GROUPS` / `SKY_SETTING_FIELD_SCHEMA` |
78
+
79
+ Note the value-read difference: toon/environment/post/tree settings are
80
+ nested (`settings[field.group][field.key]`), water/grass/flower/sky settings
81
+ are flat (`settings[field.key]`). `readFieldValueFromSettings` handles the
82
+ nested case; for flat settings pass
83
+ `getValue: (field) => settings[field.key]`.
84
+
85
+ ## createSelectRow
86
+
87
+ A plain labeled `<select>` row for the controls that live alongside the
88
+ schema-generated groups (preset pickers, debug-view selectors):
89
+
90
+ ```js
91
+ import { createSelectRow } from '@call-me-sensei/toonlab/debug';
92
+
93
+ const row = createSelectRow({
94
+ id: 'toonPreset',
95
+ label: 'Preset',
96
+ options: getToonPresetOptions().map((p) => ({ value: p.id, label: p.label })),
97
+ value: currentPreset,
98
+ onChange: (value) => setLabParams({ toonPreset: value }),
99
+ });
100
+ panelHeader.append(row);
101
+ ```
102
+
103
+ ## Field value helpers (`fieldValues.js`)
104
+
105
+ The coercion layer between schema-typed values and DOM control values, used
106
+ by the panel and exported for custom UIs:
107
+
108
+ - `readFieldValueFromSettings(settings, field)` — nested group/key read.
109
+ - `readFieldValueFromControl(control, field)` — checkbox/range/color/select
110
+ → typed value (colors become `[r, g, b]` arrays, numbers parse, etc.).
111
+ - `writeFieldControlValue(control, output, field, value)` — push a value
112
+ into a control and its `<output>`.
113
+ - `formatFieldValue(value, field)` — display formatting.
114
+ - `colorToHex(value)` / `hexToColorArray(value)` — `[r, g, b]` ↔ `#rrggbb`.
115
+ - `vectorToArray(value)` — vector-ish → plain array.
116
+
117
+ ## How the labs use it
118
+
119
+ Character Shader Lab and Environment Shader Lab consume their respective
120
+ schemas independently. Each lab's panel is a thin consumer that wires
121
+ `getValue`/`onChange` to its preset store and to
122
+ `applyToonSettingsToMaterial` or `applyEnvironmentSettingsToMaterial` for
123
+ live uniform-safe edits. Preset switching refreshes the controls from the
124
+ normalized package settings. The same schema-consumer pattern drives Water,
125
+ Sky, Grass, Tree, and Flower Labs; no lab keeps a private copy of its runtime
126
+ parameter contract.
package/docs/docs.css ADDED
@@ -0,0 +1,589 @@
1
+ /* ToonLab OSS docs — matches the labs home look (tokens duplicated per page,
2
+ same convention as home.css / settings.css). */
3
+
4
+ :root {
5
+ --tl-bg-0: #0b0c0f;
6
+ --tl-bg-1: #111318;
7
+ --tl-bg-2: #191b21;
8
+ --tl-line: rgb(242 240 233 / 0.09);
9
+ --tl-line-bright: rgb(242 240 233 / 0.18);
10
+ --tl-ink-1: #f2f0e9;
11
+ --tl-ink-2: #a6a5a1;
12
+ --tl-ink-3: #62636b;
13
+ --tl-accent: #e8332e;
14
+ --tl-accent-hot: #ff4a42;
15
+ --tl-accent-deep: #b3201f;
16
+ --tl-ao: #3d7eff;
17
+ --tl-gold: #c9a24b;
18
+ --tl-font-display: "M PLUS 1", "Zen Kaku Gothic New", "Inter", system-ui, sans-serif;
19
+ --tl-font-jp: "Zen Kaku Gothic New", "M PLUS 1", sans-serif;
20
+ --tl-font-ui: "Inter", "M PLUS 1", system-ui, -apple-system, sans-serif;
21
+ --tl-font-mono: "JetBrains Mono", ui-monospace, monospace;
22
+ --tl-ease: cubic-bezier(0.22, 1, 0.36, 1);
23
+ --tl-dur-1: 120ms;
24
+ --tl-dur-2: 220ms;
25
+ }
26
+
27
+ * {
28
+ margin: 0;
29
+ padding: 0;
30
+ box-sizing: border-box;
31
+ }
32
+
33
+ html {
34
+ scroll-behavior: smooth;
35
+ }
36
+
37
+ body {
38
+ background: var(--tl-bg-0);
39
+ color: var(--tl-ink-1);
40
+ font-family: var(--tl-font-ui);
41
+ -webkit-font-smoothing: antialiased;
42
+ }
43
+
44
+ a {
45
+ color: inherit;
46
+ text-decoration: none;
47
+ }
48
+
49
+ /* ---- Header (mirrors home-header) ---- */
50
+
51
+ .docs-header {
52
+ display: flex;
53
+ align-items: center;
54
+ justify-content: space-between;
55
+ padding: 18px 28px;
56
+ border-bottom: 1px solid var(--tl-line);
57
+ }
58
+
59
+ .docs-brand {
60
+ display: inline-flex;
61
+ align-items: center;
62
+ gap: 10px;
63
+ }
64
+
65
+ .docs-brand-mark {
66
+ display: grid;
67
+ place-items: center;
68
+ width: 30px;
69
+ height: 30px;
70
+ background: var(--tl-accent);
71
+ color: #fff;
72
+ font-family: var(--tl-font-jp);
73
+ font-weight: 900;
74
+ font-size: 17px;
75
+ clip-path: polygon(0 0, 100% 0, 100% 78%, 78% 100%, 0 100%);
76
+ }
77
+
78
+ .docs-brand-word {
79
+ font-family: var(--tl-font-display);
80
+ font-weight: 800;
81
+ letter-spacing: 0.16em;
82
+ font-size: 15px;
83
+ }
84
+
85
+ .docs-brand-tag {
86
+ font-family: var(--tl-font-mono);
87
+ font-size: 10px;
88
+ letter-spacing: 0.12em;
89
+ text-transform: uppercase;
90
+ color: var(--tl-ink-3);
91
+ border: 1px solid var(--tl-line-bright);
92
+ padding: 3px 7px;
93
+ border-radius: 2px;
94
+ }
95
+
96
+ .docs-topnav {
97
+ display: flex;
98
+ align-items: center;
99
+ gap: 26px;
100
+ }
101
+
102
+ .docs-topnav a {
103
+ font-family: var(--tl-font-display);
104
+ font-size: 13px;
105
+ font-weight: 700;
106
+ letter-spacing: 0.1em;
107
+ text-transform: uppercase;
108
+ color: var(--tl-ink-2);
109
+ transition: color var(--tl-dur-1) var(--tl-ease);
110
+ }
111
+
112
+ .docs-topnav a:hover,
113
+ .docs-topnav a[aria-current="page"] {
114
+ color: var(--tl-ink-1);
115
+ }
116
+
117
+ /* ---- Frame ---- */
118
+
119
+ .docs-frame {
120
+ display: grid;
121
+ grid-template-columns: 220px minmax(0, 1fr);
122
+ gap: 48px;
123
+ max-width: 1080px;
124
+ margin: 0 auto;
125
+ padding: 48px 24px 96px;
126
+ }
127
+
128
+ .docs-side {
129
+ position: sticky;
130
+ top: 24px;
131
+ align-self: start;
132
+ display: flex;
133
+ flex-direction: column;
134
+ gap: 14px;
135
+ }
136
+
137
+ .docs-side-label {
138
+ font-family: var(--tl-font-mono);
139
+ font-size: 11px;
140
+ letter-spacing: 0.14em;
141
+ text-transform: uppercase;
142
+ color: var(--tl-accent);
143
+ }
144
+
145
+ .docs-nav {
146
+ display: flex;
147
+ flex-direction: column;
148
+ border-left: 1px solid var(--tl-line);
149
+ }
150
+
151
+ .docs-nav a {
152
+ padding: 8px 14px;
153
+ font-size: 14px;
154
+ color: var(--tl-ink-2);
155
+ border-left: 2px solid transparent;
156
+ margin-left: -1px;
157
+ transition: color var(--tl-dur-1) var(--tl-ease);
158
+ }
159
+
160
+ .docs-nav a:hover {
161
+ color: var(--tl-ink-1);
162
+ }
163
+
164
+ .docs-nav a.active {
165
+ color: var(--tl-ink-1);
166
+ border-left-color: var(--tl-accent);
167
+ }
168
+
169
+ .docs-side-foot {
170
+ display: flex;
171
+ gap: 14px;
172
+ padding-top: 6px;
173
+ }
174
+
175
+ .docs-side-foot a {
176
+ font-size: 12px;
177
+ color: var(--tl-ink-3);
178
+ }
179
+
180
+ .docs-side-foot a:hover {
181
+ color: var(--tl-ink-1);
182
+ }
183
+
184
+ /* ---- Content ---- */
185
+
186
+ .docs-main {
187
+ min-width: 0;
188
+ max-width: 720px;
189
+ }
190
+
191
+ .docs-eyebrow {
192
+ font-family: var(--tl-font-mono);
193
+ font-size: 11px;
194
+ letter-spacing: 0.14em;
195
+ text-transform: uppercase;
196
+ color: var(--tl-accent);
197
+ margin-bottom: 14px;
198
+ }
199
+
200
+ .docs-main h1 {
201
+ font-family: var(--tl-font-display);
202
+ font-size: clamp(28px, 4vw, 38px);
203
+ font-weight: 800;
204
+ letter-spacing: -0.01em;
205
+ line-height: 1.15;
206
+ margin: 0 0 14px;
207
+ }
208
+
209
+ .docs-lede {
210
+ font-size: 16px;
211
+ line-height: 1.65;
212
+ color: var(--tl-ink-2);
213
+ margin: 0 0 36px;
214
+ max-width: 60ch;
215
+ }
216
+
217
+ .docs-main h2 {
218
+ font-family: var(--tl-font-display);
219
+ font-size: 21px;
220
+ font-weight: 700;
221
+ margin: 48px 0 12px;
222
+ padding-top: 24px;
223
+ border-top: 1px solid var(--tl-line);
224
+ }
225
+
226
+ .docs-main h3 {
227
+ font-size: 16px;
228
+ font-weight: 600;
229
+ margin: 28px 0 8px;
230
+ }
231
+
232
+ .docs-main p {
233
+ font-size: 14.5px;
234
+ line-height: 1.7;
235
+ color: var(--tl-ink-2);
236
+ margin: 0 0 14px;
237
+ max-width: 65ch;
238
+ }
239
+
240
+ .docs-main p strong,
241
+ .docs-main li strong {
242
+ color: var(--tl-ink-1);
243
+ }
244
+
245
+ .docs-main a:not(.docs-card) {
246
+ /* Lightened from --tl-ao: the UI-link blue is too dim for 14.5px body
247
+ text on --tl-bg-0 (~4:1); this holds ~8:1 in dense paragraphs. */
248
+ color: #8fb3ff;
249
+ }
250
+
251
+ .docs-main a:not(.docs-card):hover {
252
+ text-decoration: underline;
253
+ }
254
+
255
+ .docs-main ul,
256
+ .docs-main ol {
257
+ margin: 0 0 14px;
258
+ padding-left: 22px;
259
+ display: flex;
260
+ flex-direction: column;
261
+ gap: 6px;
262
+ }
263
+
264
+ .docs-main li {
265
+ font-size: 14.5px;
266
+ line-height: 1.65;
267
+ color: var(--tl-ink-2);
268
+ }
269
+
270
+ .docs-main code {
271
+ font-family: var(--tl-font-mono);
272
+ font-size: 0.92em;
273
+ background: var(--tl-bg-2);
274
+ border: 1px solid var(--tl-line);
275
+ border-radius: 2px;
276
+ padding: 1px 5px;
277
+ }
278
+
279
+ /* ---- Pro badge ---- */
280
+
281
+ .docs-pro {
282
+ display: inline-flex;
283
+ align-items: center;
284
+ font-family: var(--tl-font-mono);
285
+ font-size: 10px;
286
+ letter-spacing: 0.12em;
287
+ text-transform: uppercase;
288
+ color: var(--tl-gold);
289
+ border: 1px solid rgb(201 162 75 / 0.45);
290
+ background: rgb(201 162 75 / 0.08);
291
+ padding: 2px 7px;
292
+ border-radius: 2px;
293
+ vertical-align: 2px;
294
+ margin-left: 8px;
295
+ white-space: nowrap;
296
+ }
297
+
298
+ /* ---- Code + prompt blocks ---- */
299
+
300
+ .docs-codeblock {
301
+ position: relative;
302
+ margin: 16px 0 20px;
303
+ border: 1px solid var(--tl-line);
304
+ border-radius: 4px;
305
+ background: var(--tl-bg-1);
306
+ overflow: hidden;
307
+ }
308
+
309
+ .docs-codeblock-label {
310
+ font-family: var(--tl-font-mono);
311
+ font-size: 10.5px;
312
+ letter-spacing: 0.12em;
313
+ text-transform: uppercase;
314
+ color: var(--tl-ink-3);
315
+ padding: 8px 14px 0;
316
+ }
317
+
318
+ .docs-codeblock pre {
319
+ margin: 0;
320
+ padding: 14px;
321
+ overflow-x: auto;
322
+ }
323
+
324
+ .docs-codeblock code {
325
+ font-family: var(--tl-font-mono);
326
+ font-size: 12.5px;
327
+ line-height: 1.6;
328
+ color: var(--tl-ink-1);
329
+ background: none;
330
+ border: none;
331
+ padding: 0;
332
+ white-space: pre;
333
+ }
334
+
335
+ .docs-codeblock-copy {
336
+ position: absolute;
337
+ top: 8px;
338
+ right: 8px;
339
+ display: inline-flex;
340
+ align-items: center;
341
+ gap: 6px;
342
+ font-family: var(--tl-font-ui);
343
+ font-size: 11px;
344
+ padding: 4px 10px;
345
+ color: var(--tl-ink-2);
346
+ background: var(--tl-bg-2);
347
+ border: 1px solid var(--tl-line-bright);
348
+ border-radius: 3px;
349
+ cursor: pointer;
350
+ transition: color var(--tl-dur-1) var(--tl-ease), border-color var(--tl-dur-1) var(--tl-ease);
351
+ }
352
+
353
+ .docs-codeblock-copy:hover {
354
+ color: var(--tl-ink-1);
355
+ border-color: var(--tl-ink-3);
356
+ }
357
+
358
+ .docs-promptblock {
359
+ margin: 20px 0 28px;
360
+ }
361
+
362
+ .docs-promptblock-title {
363
+ font-weight: 600;
364
+ font-size: 14.5px;
365
+ color: var(--tl-ink-1);
366
+ }
367
+
368
+ .docs-promptblock .docs-codeblock {
369
+ margin-top: 10px;
370
+ margin-bottom: 8px;
371
+ }
372
+
373
+ .docs-promptblock .docs-codeblock code {
374
+ white-space: pre-wrap;
375
+ color: var(--tl-ink-2);
376
+ }
377
+
378
+ .docs-promptblock-note {
379
+ font-size: 13px;
380
+ color: var(--tl-ink-3);
381
+ margin: 0;
382
+ }
383
+
384
+ /* ---- Cards, callouts, tables ---- */
385
+
386
+ .docs-cards {
387
+ display: grid;
388
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
389
+ gap: 14px;
390
+ margin: 20px 0 8px;
391
+ }
392
+
393
+ .docs-card {
394
+ display: flex;
395
+ flex-direction: column;
396
+ gap: 8px;
397
+ padding: 18px;
398
+ border: 1px solid var(--tl-line);
399
+ border-radius: 4px;
400
+ background: var(--tl-bg-1);
401
+ transition: border-color var(--tl-dur-1) var(--tl-ease);
402
+ }
403
+
404
+ .docs-card:hover {
405
+ border-color: var(--tl-line-bright);
406
+ }
407
+
408
+ .docs-card strong {
409
+ color: var(--tl-ink-1);
410
+ font-size: 15px;
411
+ }
412
+
413
+ .docs-card span {
414
+ font-size: 13px;
415
+ line-height: 1.55;
416
+ color: var(--tl-ink-2);
417
+ }
418
+
419
+ .docs-card svg {
420
+ color: var(--tl-accent);
421
+ }
422
+
423
+ .docs-callout {
424
+ display: flex;
425
+ gap: 12px;
426
+ padding: 14px 16px;
427
+ margin: 16px 0 20px;
428
+ border: 1px solid var(--tl-line);
429
+ border-left: 2px solid var(--tl-accent);
430
+ border-radius: 4px;
431
+ background: linear-gradient(120deg, rgb(232 51 46 / 0.12), rgb(232 51 46 / 0.03));
432
+ font-size: 13.5px;
433
+ line-height: 1.6;
434
+ color: var(--tl-ink-2);
435
+ }
436
+
437
+ .docs-callout--pro {
438
+ border-left-color: var(--tl-gold);
439
+ background: linear-gradient(120deg, rgb(201 162 75 / 0.1), rgb(201 162 75 / 0.02));
440
+ }
441
+
442
+ .docs-callout svg {
443
+ flex-shrink: 0;
444
+ margin-top: 2px;
445
+ color: var(--tl-accent);
446
+ }
447
+
448
+ .docs-callout--pro svg {
449
+ color: var(--tl-gold);
450
+ }
451
+
452
+ .docs-table-wrap {
453
+ overflow-x: auto;
454
+ margin: 16px 0 20px;
455
+ border: 1px solid var(--tl-line);
456
+ border-radius: 4px;
457
+ }
458
+
459
+ .docs-table {
460
+ width: 100%;
461
+ border-collapse: collapse;
462
+ font-size: 13.5px;
463
+ }
464
+
465
+ .docs-table th {
466
+ text-align: left;
467
+ font-family: var(--tl-font-mono);
468
+ font-size: 10.5px;
469
+ letter-spacing: 0.12em;
470
+ text-transform: uppercase;
471
+ color: var(--tl-ink-3);
472
+ padding: 10px 14px;
473
+ border-bottom: 1px solid var(--tl-line);
474
+ background: var(--tl-bg-1);
475
+ }
476
+
477
+ .docs-table td {
478
+ padding: 10px 14px;
479
+ border-bottom: 1px solid var(--tl-line);
480
+ color: var(--tl-ink-2);
481
+ vertical-align: top;
482
+ line-height: 1.55;
483
+ }
484
+
485
+ .docs-table tr:last-child td {
486
+ border-bottom: none;
487
+ }
488
+
489
+ .docs-table td:first-child {
490
+ font-family: var(--tl-font-mono);
491
+ font-size: 12.5px;
492
+ color: var(--tl-ink-1);
493
+ white-space: nowrap;
494
+ }
495
+
496
+ .docs-step-label {
497
+ display: inline-block;
498
+ font-family: var(--tl-font-mono);
499
+ font-size: 11px;
500
+ color: var(--tl-accent);
501
+ margin-right: 8px;
502
+ }
503
+
504
+ /* ---- Rendered markdown (settings reference) ---- */
505
+
506
+ .docs-md table {
507
+ display: block;
508
+ overflow-x: auto;
509
+ border-collapse: collapse;
510
+ font-size: 13px;
511
+ margin: 14px 0 22px;
512
+ border: 1px solid var(--tl-line);
513
+ border-radius: 4px;
514
+ }
515
+
516
+ .docs-md th {
517
+ text-align: left;
518
+ font-family: var(--tl-font-mono);
519
+ font-size: 10.5px;
520
+ letter-spacing: 0.1em;
521
+ text-transform: uppercase;
522
+ color: var(--tl-ink-3);
523
+ padding: 8px 12px;
524
+ border-bottom: 1px solid var(--tl-line);
525
+ background: var(--tl-bg-1);
526
+ white-space: nowrap;
527
+ }
528
+
529
+ .docs-md td {
530
+ padding: 7px 12px;
531
+ border-bottom: 1px solid var(--tl-line);
532
+ color: var(--tl-ink-2);
533
+ vertical-align: top;
534
+ line-height: 1.5;
535
+ min-width: 60px;
536
+ }
537
+
538
+ .docs-md tr:last-child td {
539
+ border-bottom: none;
540
+ }
541
+
542
+ .docs-md td:first-child code {
543
+ color: var(--tl-ink-1);
544
+ }
545
+
546
+ .docs-md h2,
547
+ .docs-md h3 {
548
+ scroll-margin-top: 24px;
549
+ }
550
+
551
+ .docs-md h3 {
552
+ font-family: var(--tl-font-mono);
553
+ font-size: 13px;
554
+ letter-spacing: 0.04em;
555
+ color: var(--tl-ink-1);
556
+ }
557
+
558
+ /* ---- Responsive ---- */
559
+
560
+ @media (max-width: 860px) {
561
+ .docs-frame {
562
+ grid-template-columns: 1fr;
563
+ gap: 24px;
564
+ padding-top: 28px;
565
+ }
566
+
567
+ .docs-side {
568
+ position: static;
569
+ }
570
+
571
+ .docs-nav {
572
+ flex-direction: row;
573
+ flex-wrap: wrap;
574
+ border-left: none;
575
+ border-bottom: 1px solid var(--tl-line);
576
+ gap: 2px;
577
+ }
578
+
579
+ .docs-nav a {
580
+ border-left: none;
581
+ border-bottom: 2px solid transparent;
582
+ margin-left: 0;
583
+ margin-bottom: -1px;
584
+ }
585
+
586
+ .docs-nav a.active {
587
+ border-bottom-color: var(--tl-accent);
588
+ }
589
+ }