cygtut
v1.0.2
Published
JSON-driven tutorial overlay engine for web applications
Readme
CygTut
CygTut is a high-level tutorial overlay engine built on top of cyghtml 0.1.1.
Its purpose is simple:
- keep tutorial meaning above the low-level renderer
- place tutorial objects above an existing host page without rewriting that page
- resolve target-based positions and anchors
- keep tutorial runtime state, commands, and triggers
- compile the result into a final
cyghtmldocument - let
cyghtmlrender the final overlay DOM
CygTut is not a low-level HTML/CSS renderer.
It does not want to replace cyghtml.
It exists to sit above cyghtml and own tutorial behavior.
Philosophy
CygTut follows these design rules.
- It is a tutorial engine first.
- It should reuse as much of
cyghtmlas possible. - The host page should stay untouched.
- Tutorial UI should be rendered as overlay DOM above the host page.
- The most important positioning model is target-based placement.
- The final rendered result should be absolute overlay HTML/CSS.
- Grouping should compile to real parent DOM nodes.
- Final animation should be expressed as CSS.
- CygTut should own state, commands, triggers, presets, anchors, and compilation.
cyghtmlshould only receive final render data.
In short:
cygtutdecides tutorial meaning and placementcygtutcompiles the final overlay documentcyghtmlrenders it
Relationship To cyghtml
The intended architecture is:
cygtut authoring script
-> cygtut runtime state
-> cygtut compile step
-> final cyghtml document
-> cyghtml renders overlay DOMThat means:
cygtutowns tutorial meaningcygtutowns runtime variables and progressioncygtutresolves targets and anchorscygtutcomputes final overlay geometrycygtutoutputs a finalcyghtmldocumentcyghtmlmounts the overlay root and renders the document
Core Runtime Model
The most important concept in CygTut is the overlay root.
The host page already exists. CygTut does not rewrite it. Instead, it creates overlay objects above that page.
Those overlay objects are placed like this:
- select a target element on the host page
- read the target's current rectangle
- choose a target anchor and self anchor
- compute the final absolute overlay coordinates
- compile the result to
cyghtml - let
cyghtmlrender the overlay DOM
So the core model is:
existing page
-> target selected
-> target geometry read
-> tutorial object geometry computed
-> final overlay HTML/CSS generated
-> cyghtml renders itThis keeps the host page safe while still allowing tutorial UI to feel attached to real page elements.
Responsibility Split
CygTut owns
- tutorial runtime state
- tutorial variables
- commands
- triggers
- target selection
- target anchor and self anchor resolution
- object presets and tutorial object meaning
- grouping rules
- final position and size calculation
- mobile/window branching logic
- conversion into a final
cyghtmldocument
cyghtml owns
- overlay root mounting
- final top-level
vars,css, andhtmlrendering - DOM creation from
tagormarkup attrs,style,text, anditems- parent-child composition
- delayed parent resolution
- runtime event hookup
- final DOM commit
The boundary is simple:
cygtutdecides what should exist and wherecyghtmlrenders that already-decided result
How CygTut Uses cyghtml
The most important implementation rule is: CygTut should prefer reusing cyghtml features instead of recreating them.
Feature mapping:
- overlay root mounting ->
CygHtmlEngine.mount(),mountById(),mountByClass(),mountByTag() - final overlay DOM output ->
CygHtmlDocument.html - final runtime variables ->
CygHtmlDocument.vars - final CSS rules ->
CygHtmlDocument.css - real parent-child grouping ->
itemsandappendTo - host-page mounting features remain available in
cyghtml, but are not yet exposed as first-class CygTut authoring fields - DOM event binding ->
cyghtmlnodeeventsplusCygHtmlEngine.handlers - final CSS animation rendering ->
style.animation,style.transition,style.transform,style.opacity - interactive overlay behavior ->
CygHtmlEngine({ interactive })
That means CygTut should not reimplement:
- low-level DOM creation
- low-level stylesheet generation
- low-level event listener wiring
- overlay root mounting logic
- parent resolution for final HTML nodes
Instead, CygTut should focus on:
- tutorial meaning
- target lookup
- anchor resolution
- command and trigger flow
- compilation into final
cyghtmldata
Planned And Incomplete Areas
The current architecture is usable, but several important areas still need more detailed design or stronger implementation.
This section turns those areas into concrete planning notes so later code changes have a stable target.
1. Target lifecycle policy
This is one of the most important unfinished areas because target-based placement is the center of the whole runtime.
Goal
CygTut should treat host-page targets as unstable, real-world DOM dependencies. A target may already exist, appear later, disappear, move, resize, or be temporarily hidden. The runtime should define exactly what happens in each case.
Required behavior
- When a target exists:
- read its current
getBoundingClientRect() - resolve
targetAnchor - resolve
selfAnchor - compute final absolute overlay geometry
- When a target does not exist yet:
- do not crash
- do not create a wrong fallback geometry
- mark the object as unresolved for the current render pass
- skip output for that object in the compiled
cyghtmldocument
- When a target appears later:
- allow the next normal runtime render pass to resolve it
- the object should become visible without needing to be recreated by the user
- When a target disappears after previously existing:
- treat the object as unresolved again
- hide it by omitting it from the compiled output
- preserve its runtime object state unless the script explicitly removes it
- When a target moves or resizes:
- recompute geometry
- recompile
- rerender through
cyghtml
Runtime states
A target-bound object should conceptually have these states:
resolvedpending-targethidden-by-stateremoved
Even if these are not formal enum values yet, the runtime behavior should follow that model.
Observation policy
Current minimum policy:
- rerender on
resize - rerender on
scroll
Planned stronger policy:
- optional host
MutationObserver - optional
ResizeObserverfor known targets - optional throttling to avoid excessive recompilation
Boundary with cyghtml
CygTut owns:
- selector lookup
- target existence checks
- geometry resolution
- unresolved-target policy
cyghtml owns:
- rendering whatever final nodes CygTut gives it
That means unresolved targets should be handled before compilation finishes. cyghtml should never need to understand tutorial target semantics.
2. Animation system detail
The animation model now has the correct high-level shape:
enterlooppresetcustom
This section defines how that model should work more precisely.
Goal
CygTut should expose tutorial-friendly animation authoring while still compiling everything into ordinary CSS that cyghtml can render without special logic.
Phase model
Supported phases:
enter: one-time appearance animationloop: persistent or repeating animation while the object remains active
Intentional omission for now:
- no first-class
exitphase
Reason:
- object disappearance can be expressed by state changes, object replacement, or future authoring sugar
- keeping only
enterandloopkeeps the base model simpler
Authoring shape
Recommended structure:
{
"animation": {
"enter": {
"preset": "fade-in"
},
"loop": {
"custom": {
"animation": "pulse 1.2s ease-in-out infinite"
}
}
}
}Backward-compatibility is currently allowed with raw CSS-like animation objects, but the long-term preferred model is the two-phase structure above.
Preset policy
Current preset direction:
fade-inslide-upslide-downslide-leftslide-rightscale-inpulserotate
Planned rules:
- preset names are semantic authoring shortcuts
- preset output is compiler-owned CSS
- presets may inject support styles such as keyframes into the final compiled document
- timing defaults should be stable but may later become overridable per object
Custom policy
custom is the escape hatch.
It should accept CSS-facing values such as:
animationtransitiontransformopacity
CygTut should not try to outgrow CSS here. If authors need richer animation behavior, the right answer is usually to emit better final CSS, not to build a new animation engine.
Merge rules
When both phases exist:
entercontributes its one-time appearance stylingloopcontributes its persistent styling- if both define the same low-level field,
loopwins for the steady-state compiled style - if both define
animation, the compiler may combine them as comma-separated CSS animation values when appropriate
Group behavior
If animation is applied to a group object:
- the group parent receives the final CSS animation styles
- child elements should follow naturally through normal DOM inheritance/transform behavior
This is one of the main reasons grouping should compile to real parent DOM nodes.
Boundary with cyghtml
CygTut owns:
- animation authoring shape
- preset resolution
- generated support styles
- final low-level animation CSS values
cyghtml owns:
- applying the final CSS to DOM nodes
3. Responsive and device branching
CygTut already treats responsive behavior as tutorial runtime state rather than renderer logic. That direction is good, but the detailed model still needs to be made explicit.
Goal
Responsive tutorial behavior should come from tutorial state and compilation rules, not from hidden renderer magic.
Core rule
Responsive decisions belong in CygTut. cyghtml should stay unaware of concepts like mobile tutorial mode, window tutorial mode, or tutorial-specific breakpoint logic.
Recommended variable model
Use normal variables such as:
global.device = "window"global.device = "mobile"global.device = "tablet"
The host app may set these directly. CygTut reacts through normal triggers, commands, and compilation.
Planned branching styles
- Trigger-driven branching
- simplest and most explicit
- object creation and updates depend on
global.device
- Compile-time object branching
- later optional convenience layer
- for example a single authoring object may contain
desktopandmobilevariants that compile differently
Viewport recomputation
Current minimum:
- rerender on
resize - recompute all target-based geometry
Still to design more deeply:
- whether viewport-based clamping should be global or per object
- whether object-specific responsive overrides should live in the base object schema
- whether a standard breakpoint helper belongs in authoring sugar
Boundary with cyghtml
CygTut owns:
- responsive tutorial semantics
- responsive state variables
- responsive geometry and style decisions
cyghtml owns:
- rendering the final already-chosen document
4. Command coverage and flow semantics
The current command set is enough for the basic runtime, but some command behavior still needs clearer semantics.
Goal
Commands should stay small, explicit, and easy to compile into runtime state changes. Authoring convenience should be layered above them rather than making the core command system too large.
Current core command families
Structure:
CREATE_GROUPADD_OBJECTUPDATE_OBJECTREMOVE_OBJECTADD_TO_GROUPREMOVE_FROM_GROUPUNGROUP
Variables:
SET_VARINC_VARTOGGLE_VAR
Flow:
RUNIFWAIT_UNTILEMIT
Areas still needing stronger design
WAIT_UNTIL
Right now it is a placeholder. It needs a real policy.
Planned direction:
- condition-based waiting only
- no hidden time engine in the first pass
WAIT_UNTILshould suspend the current command sequence until a condition becomes true- resumption should occur through the same runtime state-change pipeline used by triggers
RUN
Needs clearer naming conventions.
Planned direction:
- allow
step:<name> - allow
scene:<name> - allow explicit named command groups later if needed
EMIT
Needs a sharper host integration contract.
Planned direction:
- stay a small bridge from tutorial runtime to host application callbacks
- do not let it become a hidden second state system
Visibility control
Still undecided whether explicit commands like these are needed:
SHOW_OBJECTHIDE_OBJECT
Current direction:
- prefer
ADD_OBJECT,UPDATE_OBJECT, andREMOVE_OBJECT - only add dedicated visibility commands if authoring becomes unnecessarily noisy without them
Boundary with cyghtml
Commands should mutate tutorial state.
They should not directly manipulate low-level DOM.
The only DOM output should be the compiled result passed to cyghtml.
5. Tutorial object schema depth
The common object model is defined, but some object families still need deeper planning.
Goal
Keep the object model opinionated enough to feel tutorial-native, while keeping the final compiled output simple enough for cyghtml.
Current first-party object set
tooltiphighlighttextbuttonmaskgroupimageprogress
Schema questions still to settle
- Which fields are truly universal?
targettargetAnchorselfAnchoroffsetautoPlacementxywidthheightstyleattrsvarseventstriggersanimation
- Which fields should remain object-specific?
titleandtextfor tooltipspaddingfor highlightssrcandaltfor imagesvalueandmaxfor progress
- Should richer content exist? Possible future directions:
- richer tooltip body content
- icon support
- structured content blocks
- inline action rows
- Should groups gain more layout helpers? Possible future directions:
- helper stacking rules
- built-in gap helpers
- local alignment helpers
Current direction:
- default group children remain absolute
- richer layout helpers, if added, should still compile into plain HTML/CSS and not replace DOM semantics
6. External host integration
CygTut already supports direct variable control and uses cyghtml event handlers underneath, but host integration still needs a sharper documented contract.
Goal
Host apps should be able to control tutorial progression without needing to understand the low-level overlay renderer.
Current public direction
Public control stays state-oriented:
getVarsetVarupdateVarssubscribegetSnapshot
Mount control may also be exposed by delegating to cyghtml:
mountmountByIdmountByClassmountByTagunmount
Areas still needing design
EMITcallback registry
- where host callbacks are registered
- what payload shape they receive
- whether they can return values or only perform side effects
- Debugging and introspection
getRendererDocument()is already exposed as a debug-oriented public API- the remaining design question is how stable its compiled payload contract should be across future versions
- whether more renderer introspection should stay limited to debug workflows
- Boundary discipline
- which
cyghtmlmethods should stay hidden - which
cyghtmlcapabilities are safe to expose throughcygtut
Current direction:
- expose only what strengthens tutorial control
- keep raw low-level DOM rendering concerns inside
cyghtml
7. Testing and example coverage
This is more of a delivery gap than a design gap, but it matters a lot.
Goal
Examples and tests should prove the contract between tutorial authoring, runtime state, compilation, and final cyghtml rendering.
Still needed
- A minimal real tutorial example
- target-based highlight
- target-based tooltip
- button-triggered step progression
- A group example
- group parent positioned from a target
- children authored with local coordinates
- parent CSS animation affecting all children
- An animation example
enterpresetlooppresetcustomanimation object
- Runtime resilience tests
- missing target
- target appearing later
- resize reflow
- scroll reflow
- grouped child local coordinates
- Compilation inspection example
- show exactly how a CygTut object set becomes a final
cyghtmldocument
Current direction
Examples should not be treated as decoration. They should act as executable architecture checks.
Important Features
1. Overlay-first model
CygTut is overlay-first. The final UI always lives above the host page.
There is no separate tutorial layer system in the new direction.
The overlay root from cyghtml is enough.
If CygTut needs internal containers, it can compile them as normal HTML group nodes.
2. Target-based placement
Tutorial objects may point to host page targets. Examples:
.login-button#search[data-product-card='1']
CygTut reads the target rectangle and places overlay objects accordingly. The original host element is not modified.
3. Anchors
When a target exists, CygTut can use:
targetAnchorselfAnchoroffsetautoPlacement
This allows:
- exact highlight overlays
- tooltips below, above, left, or right of targets
- callouts aligned to precise target points
- optional auto-flip behavior when a target-based overlay would leave the viewport
4. Fixed tutorial object types
CygTut still benefits from high-level tutorial object meaning. Suggested object types:
highlighttooltiptextbuttonmaskgroup- optional later:
image,progress
These are tutorial concepts.
They do not need to exist as low-level cyghtml concepts.
CygTut compiles them into plain HTML/CSS.
5. Grouping
Grouping should become real DOM grouping.
A group compiles to a real parent div.
Rules:
- the group itself is an overlay object
- its children render inside it
- child positioning is absolute by default
- child coordinates are resolved relative to the group's final position
- parent style and parent animation naturally affect children
This is much more stable than trying to animate separate siblings independently.
6. CSS-based animation
Animation should still be expressed through final CSS, but the tutorial model is now simpler.
CygTut supports two animation phases:
enterloop
Each phase may be defined in one of two ways:
presetcustom
Examples:
enter.preset = "fade-in"loop.preset = "pulse"enter.custom = { "animation": "fadeIn 220ms ease-out forwards" }loop.custom = { "animation": "pulse 1.2s ease-in-out infinite" }
The compiler turns these definitions into plain CSS values such as:
animationtransitiontransformopacity
and passes the final result down to cyghtml.
7. Runtime variables
CygTut still needs runtime variables. Common examples:
global.stepglobal.sceneglobal.deviceglobal.completedobject.clicks
These variables drive tutorial behavior.
8. Triggers
CygTut remains trigger-driven.
Normal trigger model:
- a variable changes
- matching triggers are re-evaluated
- commands run
- tutorial object state changes
- a new
cyghtmldocument is compiled - the overlay is re-rendered
9. External control
CygTut should allow external reads and writes. Examples:
getVar("global.step")setVar("global.step", 2)updateVars({ "global.device": "mobile" })
That lets host applications control tutorial state directly.
Mount note:
- call
mount()ormountBy*()beforestart()if you want the first render to use a custom mount host - if you never call them,
cyghtmlfalls back to its default root mounting behavior
Top-Level Authoring Keys
A CygTut script is tutorial-oriented, not render-oriented.
The top-level authoring keys are:
metavarsbootstepsscenestriggers
Example:
{
"meta": {
"bindings": {
"steps": { "path": "global.step", "initial": 1 },
"device": { "path": "global.device", "initial": "window" }
}
},
"vars": {
"global.completed": false
},
"boot": [
{
"type": "ADD_OBJECT",
"object": {
"id": "login-highlight",
"type": "highlight",
"target": ".login-button"
}
}
],
"steps": {
"1": [
{
"type": "ADD_OBJECT",
"object": {
"id": "login-tooltip",
"type": "tooltip",
"target": ".login-button",
"targetAnchor": "bottom",
"selfAnchor": "top",
"offset": { "x": 0, "y": 12 },
"title": "Login Guide",
"text": "Click the login button to continue."
}
}
]
}
}This is still CygTut authoring JSON.
It is not the final cyghtml document.
Tutorial Object Model
Every tutorial object starts from a common shape.
Common keys:
idtypetargettargetAnchorselfAnchoroffsetxywidthheightclassNameattrsstylevarseventstriggersanimationgroupId
Common meaning
id: unique tutorial object idtype: tutorial object kind such astooltip,highlight,button,grouptarget: host selector used for geometry lookuptargetAnchor: anchor point on the host targetselfAnchor: anchor point on the overlay object itselfoffset: extra x/y shift after anchor placementautoPlacement: optional collision-aware fallback placement for target-based objectsx,y,width,height: direct geometry values when not target-drivenclassName,attrs,style: extra compiled HTML/CSS surfacevars: object-local runtime valuesevents: object-level event commandstriggers: object-level trigger rulesanimation: animation definition usingenter/loop, each withpresetorcustomgroupId: parent group reference in runtime state
Object-specific keys
Examples:
tooltip:title,texthighlight:paddingbutton:texttext:textimage:src,altprogress:value,max
Top-Level meta
meta defines authoring-time or runtime wiring information.
The most useful early use is bindings.
Example:
{
"meta": {
"bindings": {
"steps": { "path": "global.step", "initial": 1 },
"scenes": { "path": "global.scene", "initial": "intro" },
"device": { "path": "global.device", "initial": "window" }
}
}
}Recommended uses:
- initial runtime bindings
- naming common progression variables
- keeping authoring convenient without hard-coding engine internals
Top-Level vars
vars defines runtime tutorial state.
Example:
{
"vars": {
"global.step": 1,
"global.scene": "intro",
"global.device": "window",
"global.completed": false
}
}Recommended scopes:
global.*object.*- later if needed:
group.*
Important rule:
stepandsceneare not special engine systems- they are just common variable names
Top-Level boot
boot contains commands that should run when the tutorial starts.
Example:
{
"boot": [
{
"type": "ADD_OBJECT",
"object": {
"id": "intro-tooltip",
"type": "tooltip",
"target": ".hero-button"
}
}
]
}Typical uses:
- create initial tutorial objects
- initialize stateful UI pieces
- prepare default tutorial context
Top-Level steps
steps is a convenience authoring section for ordered progression.
Example:
{
"steps": {
"1": [
{
"type": "ADD_OBJECT",
"object": {
"id": "tip-1",
"type": "tooltip",
"target": ".login-button"
}
}
],
"2": [
{
"type": "UPDATE_OBJECT",
"id": "tip-1",
"patch": {
"text": "Now click the password field."
}
}
]
}
}This remains authoring sugar over normal variable-driven runtime behavior.
Internally, step is still just state.
Top-Level scenes
scenes is a convenience authoring section for named tutorial states.
Example:
{
"scenes": {
"intro": [
{
"type": "ADD_OBJECT",
"object": {
"id": "intro-copy",
"type": "text",
"text": "Welcome."
}
}
],
"done": [
{
"type": "SET_VAR",
"key": "global.completed",
"value": true
}
]
}
}Like step, scene is still just variable-driven state.
The section exists for authoring comfort.
Top-Level triggers
triggers define runtime reactions to variable changes.
Example:
{
"triggers": [
{
"watch": ["global.step", "global.scene"],
"when": "global.step === 2 && global.scene === 'intro'",
"run": [
{ "type": "SET_VAR", "key": "global.scene", "value": "done" }
]
}
]
}Conditions should support:
&&||!===!==>>=<<=- parentheses
()
Commands
CygTut still owns tutorial commands.
Structure commands
CREATE_GROUPADD_OBJECTUPDATE_OBJECTREMOVE_OBJECTADD_TO_GROUPREMOVE_FROM_GROUPUNGROUP
Variable commands
SET_VARINC_VARTOGGLE_VAR
Flow commands
RUNIFWAIT_UNTILEMIT
Animation model
Animation is an object-level definition, not a separate low-level renderer command system.
Recommended shape:
animation.enteranimation.loop
Each one may contain:
presetcustom
Example:
{
"animation": {
"enter": { "preset": "fade-in" },
"loop": { "preset": "pulse" }
}
}The compiler resolves preset names into final CSS animation values and injects the required support styles into the compiled cyghtml document.
Target Lifecycle
Target handling is central to CygTut, so the runtime needs clear rules.
Current direction:
- if a target exists, compute geometry from its current
getBoundingClientRect() - target-following is always on for target-based objects
- if
autoPlacementis enabled, try fallback anchor combinations when the first placement would leave the viewport - if a target does not exist yet, skip rendering that object for the current pass
- if the host layout changes, recompute geometry and render again
The current runtime already re-renders on:
- window
resize - window
scroll
That keeps target-bound objects attached to moving page geometry during the normal tutorial lifecycle.
Positioning Model
Positioning remains a CygTut concern.
cyghtml should receive already-computed values.
CygTut should handle:
- host target lookup
- reading
getBoundingClientRect() - target anchor resolution
- self anchor resolution
- offset application
- target-following as a default behavior for all target-based objects
- optional
autoPlacementfallback when a placement would leave the viewport - final absolute
left/top/width/height - optional viewport clamping
- device-based layout branching
So the boundary stays simple:
- CygTut computes geometry
- cyghtml renders geometry
Events And Object-Local State
CygTut may still expose object-level events and object-level variables.
Example:
{
"id": "next-btn",
"type": "button",
"vars": {
"clicks": 0
},
"events": {
"onClick": [
{ "type": "INC_VAR", "key": "object.clicks", "value": 1 }
]
},
"triggers": [
{
"watch": ["object.clicks"],
"when": "object.clicks >= 1",
"run": [
{ "type": "SET_VAR", "key": "global.step", "value": 2 }
]
}
]
}That keeps local state local while still allowing it to move the global tutorial flow forward.
Final Render Shape
The compiled result should be a plain cyghtml document.
Example:
{
"vars": {
"--tip-left": "120px",
"--tip-top": "240px"
},
"css": {
".cygtut-tooltip": {
"position": "absolute",
"left": "var(--tip-left)",
"top": "var(--tip-top)",
"width": "280px",
"padding": "16px",
"borderRadius": "14px",
"background": "#111827",
"color": "#ffffff"
}
},
"html": [
{
"tag": "div",
"attrs": {
"id": "login-tooltip",
"class": "cygtut-tooltip"
},
"appendTo": "root",
"items": [
{
"tag": "h3",
"text": "Login Guide"
},
{
"tag": "p",
"text": "Click the login button to continue."
}
]
}
]
}That final document is the only thing cyghtml needs to know.
Processing Pipeline
This section describes how a CygTut script should move through the runtime, which internal areas are responsible for each stage, and in what order the work happens.
End-To-End Flow
At a high level, the runtime flow is:
authoring script
-> normalizeScript
-> StateStore
-> CommandRunner / TriggerRuntime
-> target + anchor resolution
-> compileToCygHtml
-> CygHtmlEngine.render()Step 1: Script Enters The Runtime
Files:
src/spec/Types.tssrc/spec/normalizeScript.ts
The script begins as tutorial authoring data.
Responsibilities here:
- validate top-level keys
- normalize optional authoring sugar
- prepare a runtime-friendly representation
At this stage, nothing has been rendered yet.
Step 2: Initialize State
Files:
src/runtime/StateStore.tssrc/runtime/CygTutEngine.ts
Responsibilities here:
- build the initial variable state
- apply
meta.bindings - apply top-level
vars - prepare subscriptions and runtime snapshots
At this point, CygTut has runtime state but still no overlay DOM.
Step 3: Run boot
Files:
src/runtime/CommandRunner.tssrc/runtime/CygTutEngine.ts
Responsibilities here:
- run initial startup commands
- create initial tutorial object state
- prepare the initial tutorial context
Step 4: Evaluate Triggers
Files:
src/runtime/TriggerRuntime.tssrc/runtime/CommandRunner.ts
Responsibilities here:
- watch variable changes
- evaluate trigger conditions
- run matching command lists
This happens both at startup and after later state changes.
Step 5: Produce The Current Tutorial Object Tree
Files:
src/runtime/CygTutEngine.tssrc/presets/*
Responsibilities here:
- keep the current tutorial object state
- maintain groups and object relationships
- resolve which tutorial objects currently exist
This is still tutorial-level state, not final HTML.
Step 6: Resolve Targets And Anchors
Files:
src/compiler/positionResolver.tssrc/compiler/anchorResolver.ts
Responsibilities here:
- find current host targets
- read target rectangles
- resolve target anchor points
- resolve self anchor points
- compute final absolute overlay coordinates
- optionally clamp or branch by device
At the end of this step, geometry is ready.
Step 7: Compile To cyghtml
Files:
src/compiler/compileToCygHtml.tssrc/compiler/objectCompilers.ts
Responsibilities here:
- convert tutorial objects into final
vars,css, andhtml - compile groups into real parent nodes
- compile animation meaning into CSS
- emit a complete
cyghtmldocument
After this step, CygTut has stopped being a tutorial-only model and produced a renderable overlay document.
Step 8: Render Through cyghtml
Files:
src/runtime/CygTutEngine.ts- internal
CygHtmlEngineinstance fromcyghtml
Responsibilities here:
- pass the compiled document to
cyghtml - let
cyghtmlmount the overlay root - let
cyghtmlrender the final DOM
This is the point where the tutorial becomes visible on screen.
Step 9: React To Changes
Files:
src/runtime/StateStore.tssrc/runtime/TriggerRuntime.tssrc/compiler/compileToCygHtml.tscyghtml
When an event, command, or external setVar changes runtime state:
- vars change
- triggers are re-evaluated
- tutorial object state updates
- geometry is recomputed if needed
- a new
cyghtmldocument is compiled cyghtml.render()runs again
This is the normal rerender loop.
Why This Pipeline Matters
This processing order makes the architecture clear.
It allows:
- tutorial-friendly authoring
- target-based geometry
- real grouping
- CSS-based animation
- clean separation from the low-level renderer
The design boundary stays simple:
cygtutturns tutorial meaning into final overlay datacyghtmlturns that final overlay data into DOM
Public Runtime API
The public runtime shape is:
const tut = new CygTut({ script })The runtime currently exposes these methods:
start()destroy()mount(target?)mountById(id)mountByClass(className)mountByTag(tagName)unmount()run(name)getVar(path)setVar(path, value)updateVars(record)getSnapshot()getRendererDocument()subscribe(listener)
The engine also has an internal compile step and an internal CygHtmlEngine. getRendererDocument() is exposed as a debug-oriented API for inspecting the compiled cyghtml document, while low-level renderer control should still remain behind the CygTut boundary for normal users.
Recommended Public Usage
Vanilla usage
import { CygTut } from "cygtut";
const tut = new CygTut({ script });
tut.mountById("app");
await tut.start();
tut.setVar("global.step", 2);
tut.setVar("global.device", "mobile");
console.log(tut.getVar("global.scene"));
tut.destroy();React usage
import { useRef } from "react";
import { CygTut, type CygTutHandle } from "cygtut/react";
export default function App() {
const tutRef = useRef<CygTutHandle>(null);
return (
<>
<CygTut ref={tutRef} script={script} />
<button onClick={() => tutRef.current?.setVar("global.step", 2)}>
next
</button>
</>
);
}Source Structure
The file structure reflects the new architecture.
src/
compiler/
compileToCygHtml.ts
objectCompilers.ts
positionResolver.ts
anchorResolver.ts
runtime/
CygTutEngine.ts
CommandRunner.ts
TriggerRuntime.ts
StateStore.ts
spec/
Types.ts
normalizeScript.ts
presets/
tooltip.ts
highlight.ts
button.ts
mask.ts
group.ts
wrappers/
vanilla.ts
react.tsx
index.tsThis is the intended direction for the new version of CygTut.
File Roles
src/compiler/compileToCygHtml.ts
Main compiler entry.
Responsibilities:
- convert current tutorial state into a final
cyghtmldocument
src/compiler/objectCompilers.ts
Responsibilities:
- turn tutorial object kinds into HTML/CSS structures
- for example: tooltip -> compiled HTML container + CSS vars + classes
src/compiler/positionResolver.ts
Responsibilities:
- compute final overlay coordinates
- convert target-relative rules into final absolute values
src/compiler/anchorResolver.ts
Responsibilities:
- resolve
targetAnchorandselfAnchor - compute anchor points from target and object rectangles
src/runtime/CygTutEngine.ts
Responsibilities:
- serve as the public runtime entry
- own tutorial state and lifecycle
- own the internal
CygHtmlEngineinstance
src/runtime/CommandRunner.ts
Responsibilities:
- execute tutorial commands
src/runtime/TriggerRuntime.ts
Responsibilities:
- evaluate watched variables
- run matching command lists
src/runtime/StateStore.ts
Responsibilities:
- store tutorial vars and snapshots
- expose get/set/update/subscribe-style behavior
src/spec/Types.ts
Responsibilities:
- define authoring types
- define tutorial object definitions
- define command and trigger types
src/spec/normalizeScript.ts
Responsibilities:
- normalize authoring input into internal runtime-ready data
src/presets/*
Responsibilities:
- define built-in tutorial object presets
- define shared default HTML/CSS generation behavior
src/wrappers/*
Responsibilities:
- provide Vanilla and React integration
src/index.ts
Responsibilities:
- expose the package public API
Why This Structure Fits The New Direction
This structure makes the split clear.
specdefines the tutorial languageruntimeowns state and flowcompilerturns that state intocyghtmlpresetsdefine tutorial object meaningwrappersexpose the runtime to applications
That is much closer to the actual architecture we want than the older engine/renderer split.
Installation
npm install cygtutCygTut uses cyghtml internally.
If you want both directly:
npm install cygtut cyghtmlSummary
CygTut is a tutorial engine above cyghtml.
It should:
- keep tutorial meaning and runtime state
- resolve target-based placement
- compile groups into real parent nodes
- express final animation as CSS
- compile the final result into a
cyghtmldocument - let
cyghtmlrender that document
And it should deliberately stop there.
Low-level overlay rendering belongs in cyghtml.
High-level tutorial meaning belongs in cygtut.
