{"id":"dontmineatnight/tutorial","name":"tutorial","scope":"dontmineatnight","platform":"roblox","description":"Reusable Roblox onboarding system with 2D and 3D guidance.","version":"0.4.5","latest":"0.4.5","versions":["0.1.0","0.1.1","0.1.2","0.1.3","0.1.4","0.1.5","0.2.0","0.2.1","0.3.0","0.4.1","0.4.2","0.4.3","0.4.4","0.4.5"],"license":"MIT","licenseRating":"safe","licenseCaveats":[],"licenseVerified":true,"dependencies":{"synttx/scythe":{"version":"^1.2.1","alias":"Scythe"}},"integrity":"c7da1dc97a92ee16423d11784b65d3afca726ac04455f10e45bd03df21b13432","likes":0,"downloads":0,"install":"forest install dontmineatnight/tutorial","url":"https://forest.dev/p/roblox/dontmineatnight/tutorial","files":"https://api.forest.dev/ai/package/roblox/dontmineatnight/tutorial/files","readme":"# Tutorial\n\nA small, client-side onboarding package for Roblox experiences.\n\nTutorial presents guidance around UI and world targets while leaving tutorial\ncontent, input, game actions, and progression to the calling experience. It\nprovides:\n\n- **Spotlight guidance**: a screen-space focus, tap indicator, and off-screen\n  arrow for UI or world targets.\n- **Cinematic guidance**: an animated focused hole or letterbox overlay.\n- **3D guidance**: optional highlights, beams, and world markers.\n\nTutorial does not render toast content, capture input, disable movement, or\nadvance steps based on gameplay actions.\n\n## Installation\n\nAdd Tutorial to a Wally project:\n\n```toml\n[dependencies]\nTutorial = \"dontmineatnight/tutorial@0.4.5\"\n```\n\nThen require it from the installed package:\n\n```luau\nlocal ReplicatedStorage = game:GetService(\"ReplicatedStorage\")\n\nlocal Tutorial = require(ReplicatedStorage.Packages.Tutorial)\n```\n\n## Quick start\n\n```luau\nlocal Players = game:GetService(\"Players\")\nlocal ReplicatedStorage = game:GetService(\"ReplicatedStorage\")\n\nlocal Tutorial = require(ReplicatedStorage.Packages.Tutorial)\nlocal playerGui = Players.LocalPlayer:WaitForChild(\"PlayerGui\")\n\nlocal tutorial = Tutorial.new({\n\tsteps = {\n\t\t{\n\t\t\tid = \"open-inventory\",\n\t\t\ttitle = \"Open your inventory\",\n\t\t\tdescription = \"Select the inventory button to continue.\",\n\t\t\tpresentation = {\n\t\t\t\tscreenTarget = function()\n\t\t\t\t\tlocal button = playerGui:FindFirstChild(\"InventoryButton\", true)\n\t\t\t\t\tif button and button:IsA(\"GuiObject\") then\n\t\t\t\t\t\treturn button\n\t\t\t\t\tend\n\t\t\t\t\treturn nil\n\t\t\t\tend,\n\t\t\t\tscreenMode = \"focusAndTap\",\n\t\t\t\tinputHints = {\n\t\t\t\t\tkeyboard = \"Press I\",\n\t\t\t\t\tgamepad = \"Press the inventory button\",\n\t\t\t\t\ttouch = \"Tap the inventory button\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tonStepChanged = function(step, _, _, target)\n\t\t-- Render step.title, step.description, and target in your own UI.\n\tend,\n\tonComplete = function()\n\t\t-- Remove the experience's instruction UI.\n\tend,\n})\n\ntutorial:start()\n\n-- After the experience has confirmed the action:\n-- tutorial:complete()\n```\n\nUse functions for targets that can be created, replaced, or moved while a\nstep is active. Tutorial evaluates those functions during presentation\nupdates and treats invalid or unavailable targets as absent.\n\n## Client API\n\nCreate a controller with `Tutorial.new(options)`.\n\n| Option | Description |\n| --- | --- |\n| `steps` | Required ordered list of step inputs. |\n| `presentation` | A `Tutorial.Presentation` instance, or `false` to render nothing. |\n| `presentationOptions` | Options used to create the default presentation. |\n| `startStepId` | Optional initial step ID. |\n| `onStepChanged` | Receives `(step, index, count, screenTarget)`. |\n| `onStop` | Runs when an active tutorial is stopped or destroyed. |\n| `onComplete` | Receives the last active step. |\n\nController methods:\n\n- `start(stepId?)` starts the current or named step.\n- `stop()` hides guidance without completing the tutorial.\n- `setStep(stepId)` shows a named step.\n- `advance()` moves to the next step, completing at the end.\n- `skip()` completes the tutorial locally.\n- `complete()` hides guidance and invokes `onComplete`.\n- `destroy()` disconnects the controller and destroys owned presentation.\n- `refresh()` updates dynamic targets immediately.\n- `getCurrentStep()` returns `(step, index)` while running.\n- `isRunning()` and `isCompleted()` expose controller state.\n- `getPresentation()` returns the presentation when one is enabled.\n\nA presentation provides `show`, `hide`, `refresh`, `getScreenTarget`, and\n`destroy`. The `screenTarget` passed to `onStepChanged` is the target resolved\nwhen that step was shown; call `getScreenTarget()` after `refresh()` for the\ncurrent target.\n\nA controller owns the default presentation created from `presentationOptions`.\nIf an existing presentation is supplied, the caller owns it; controller\ndestruction hides it but does not destroy it.\n\n`advance`, `skip`, and `complete` are local operations. For a\nserver-authoritative tutorial, let the experience call `setStep` or\n`complete` only after its own server confirmation.\n\n## Step presentation\n\nTutorial passes `title`, `description`, and `inputHints` to the experience but\nonly uses target fields for visual presentation.\n\n```luau\npresentation = {\n\tscreenTarget = GuiObject or function() -> GuiObject?,\n\tscreenMode = \"focus\" | \"tap\" | \"focusAndTap\" | \"letterbox\" | \"none\",\n\tworldTarget = BasePart | Model | Vector3 or function() -> target?,\n\tworldOrigin = BasePart | Model | Vector3 or function() -> origin?,\n\tworldMode = \"beam\" | \"highlight\" | \"marker\" | \"all\" | \"none\",\n\tinputHints = {\n\t\tkeyboard = \"...\",\n\t\tgamepad = \"...\",\n\t\ttouch = \"...\",\n\t},\n}\n```\n\nIf `screenTarget` is omitted and `worldTarget` is supplied, spotlight guidance\nprojects the world target into screen space. It follows the target and shows an\nedge arrow while the target is outside the viewport. The default screen\npresentation also shows an animated hand at the focus target; set\n`screen.showHand = false` to disable it or provide `screen.handImage` to replace\nit. The default hand image is `rbxassetid://97493945008237`. Set\n`screen.showTapIndicator = false` or `screen.showEdgeArrow = false` to hide\nthose optional indicators while keeping the focus and hand.\n\n`screenMode = \"letterbox\"` shows the screen presentation's top and bottom bars\nand does not require a target. The bar fraction and dim transparency are\nconfigured with `ScreenGuidanceOptions`.\n\nWorld presentation includes an animated chevron trail from the local player to\nthe target whenever world guidance is active. Set `showGuideTrail = false` to\ndisable it. It uses text chevrons and has no external asset ID. World\npresentation can also use a `BillboardGui` or `Model` as `markerTemplate`. For\nmodel markers, `markerOrientation`, `markerDistance`, and `markerTargetOffset`\ncontrol placement and orientation. `markerTargetPadding` reserves space from\nthe target when `markerDistance` or `markerOrientation` is also supplied.\n\n## Reusing visual assets\n\nTemplates are optional and are cloned by Tutorial:\n\n```luau\nlocal presentation = Tutorial.Presentation.new({\n\tscreen = {\n\t\tfocusTemplate = ReplicatedStorage.Assets.TutorialFocus,\n\t\ttapTemplate = ReplicatedStorage.Assets.TutorialTap,\n\t\tedgeArrowTemplate = ReplicatedStorage.Assets.TutorialArrow,\n\t},\n\tworld = {\n\t\tbeamTemplate = ReplicatedStorage.Assets.TutorialBeam,\n\t\thighlightTemplate = ReplicatedStorage.Assets.TutorialHighlight,\n\t\tmarkerTemplate = ReplicatedStorage.Assets.TutorialMarker,\n\t},\n})\n```\n\nTemplates provide the visual contents and structure. Tutorial owns the\npresentation properties needed to place, animate, and control the clones. For\nexample, screen templates receive Tutorial's position, size, anchor, z-index,\nand input settings; BillboardGui markers receive Tutorial's size, offset,\n`AlwaysOnTop`, and enabled state; and Highlights receive Tutorial's adornee,\ndepth, colors, transparencies, and enabled state. The original template\ninstances are never modified.\n\n## Cinematic overlay\n\n`Tutorial.CinematicOverlay` is a separate shared overlay for explicit\ncinematic transitions:\n\n```luau\nlocal overlay = Tutorial.CinematicOverlay\n\noverlay.ShowLetterbox({\n\tbarFraction = 0.12,\n\ttransparency = 0.35,\n})\noverlay.Focus(targetGui, {\n\tscaleFactor = 1,\n\ttransparency = 0.35,\n})\noverlay.Hide()\noverlay.Destroy()\n```\n\n`Focus` follows a target while it remains in the local player's `PlayerGui` and\nits rendered ancestors remain visible. `ShowLetterbox` creates animated top\nand bottom bars. Both transitions use short Sine/InOut animations; their render\nconnections and completed tweens are released automatically. Call `Destroy`\nwhen the experience no longer needs the shared overlay.\n\n## License\n\nMIT\n","readmeTruncated":false}