Agent Template
Build a Boat Blueprint Co-Pilot
Plan Build A Boat for Treasure creations, budget gold, and keep a separate library of blueprints without changing existing Roblox saves.
Roblox
Build A Boat for Treasure
building
blueprints
gold budgeting
bash
Oct 17, 2026
1 use
Preview Mode
This is a preview with sample data. The template uses placeholders like
which will be replaced with actual agent data.
About This Template
Build a Boat Blueprint Co-Pilot is a browser-executable AI agent template built on AgentOp. It runs entirely in the browser using Python (via Pyodide) and can be deployed without a server — just download the generated HTML file and open it locally or host it anywhere.
Topics
Roblox
Build A Boat for Treasure
building
blueprints
gold budgeting
Template Preview
Template Metadata
- Slug
- build-a-boat-blueprint-co-pilot
- Created By
- bash
- Created
- Oct 17, 2026
- Usage Count
- 1
Tags
Roblox
Build A Boat for Treasure
building
blueprints
gold budgeting
Code Statistics
- HTML Lines
- 46
- CSS Lines
- 1
- JS Lines
- 112
- Python Lines
- 39
Source Code
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ agent_name }}</title>
<style>{{ css_code }}</style>
</head>
<body>
<div class="app-shell">
<header class="masthead">
<div class="brand-mark" aria-hidden="true">⛵</div>
<div><p class="eyebrow">BUILD A BOAT FOR TREASURE · BLUEPRINT DESK</p><h1>{{ agent_name }}</h1><p class="subtitle">{{ description }}</p></div>
</header>
<div class="notice">🛡️ Your Roblox builds are untouched. Loading and saving here affects browser blueprints only; gold purchases are suggestions, never transactions.</div>
<div class="workspace">
<section class="panel controls" aria-labelledby="plan-heading">
<div class="panel-head"><span class="step">01</span><div><h2 id="plan-heading">Shape your boat</h2><p>Set a goal, inventory, and spending limit.</p></div></div>
<form id="build-form" novalidate>
<label for="build-name">Blueprint name</label><input id="build-name" type="text" maxlength="70" placeholder="e.g. River Runner Mk 1" required>
<label for="goal">Build goal</label><select id="goal"><option value="treasure run">Reach the treasure</option><option value="starter boat">Build a beginner boat</option><option value="multiplayer boat">Carry a crew</option><option value="themed ship">Make a themed ship</option><option value="custom">Custom boat idea</option></select>
<p id="goal-hint" class="hint">Prioritize a survivable trip toward the treasure.</p>
<label for="budget">Maximum gold to spend</label><div class="input-unit"><input id="budget" type="number" min="0" max="1000000" step="1" value="0" required><span>gold</span></div>
<label for="inventory">Blocks and parts you already own <span class="optional">optional</span></label><textarea id="inventory" rows="4" maxlength="2500" placeholder="e.g. 40 wood blocks, 8 metal blocks, 2 seats, 1 motor"></textarea>
<label for="constraints">Boat idea or constraints <span class="optional">optional</span></label><textarea id="constraints" rows="3" maxlength="1200" placeholder="e.g. two players, compact hull, no rare parts"></textarea>
<p id="form-error" class="error hidden" role="alert"></p>
<button id="generate-btn" class="primary" type="submit" disabled>🧭 Draft boat blueprint</button>
</form>
</section>
<section class="panel output" aria-labelledby="blueprint-heading">
<div class="panel-head"><span class="step">02</span><div><h2 id="blueprint-heading">Boat blueprint</h2><p id="status" role="status" aria-live="polite">Initializing blueprint desk…</p></div></div>
<div id="results-container" aria-live="polite"><div class="empty-state"><div class="empty-icon" aria-hidden="true">🗺️</div><h3>A clear plan before you place a block</h3><p>Draft a blueprint to get:</p><ul><li>🧱 A parts list based on your inventory</li><li>📐 An ordered build sequence</li><li>🪙 Gold suggestions within your limit</li><li>🛡️ A checklist to protect existing saves</li></ul></div></div>
<button id="save-btn" class="secondary" type="button" disabled>📌 Save blueprint in this browser</button>
</section>
<aside class="panel library" aria-labelledby="library-heading">
<div class="panel-head"><span class="step">03</span><div><h2 id="library-heading">Blueprint library</h2><p>Load a saved plan without replacing another.</p></div></div>
<label for="saved-plans">Saved browser blueprints</label><select id="saved-plans"><option value="">No blueprint selected</option></select>
<button id="load-btn" class="secondary" type="button" disabled>📂 Load selected blueprint</button>
<p class="hint">Blueprints live in this browser only. Loading one displays its plan; it does not load a Roblox save slot.</p>
</aside>
</div>
</div>
<div id="loading-overlay" class="loading-overlay hidden" role="status" aria-live="polite"><div class="loading-card"><span class="spinner" aria-hidden="true"></span><strong>Sketching your boat blueprint…</strong><span>Checking your goal and gold limit.</span></div></div>
<script>{{ js_code }}</script>
</body>
</html>
:root{--sea:#102d40;--deep:#092233;--teal:#087e81;--teal-dark:#07676a;--sand:#f5f2e9;--paper:#fffefa;--ink:#18303d;--muted:#596f78;--line:#d9e3df;--gold:#f2b84b;--danger:#ae303c;--radius:18px;--shadow:0 12px 35px rgba(9,34,51,.10);font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;color:var(--ink);background:var(--sand)}*{box-sizing:border-box}body{margin:0;min-height:100vh}.app-shell{max-width:1640px;margin:auto;padding:34px 32px 60px}.masthead{display:flex;align-items:center;gap:20px;margin-bottom:20px}.brand-mark{display:grid;place-items:center;width:64px;height:64px;border-radius:20px;background:var(--sea);font-size:32px;flex:none}.eyebrow{margin:0 0 5px;color:var(--teal-dark);font-size:.72rem;font-weight:800;letter-spacing:.16em}h1{margin:0;color:var(--deep);font-size:clamp(1.8rem,3vw,2.65rem);letter-spacing:-.04em}.subtitle{margin:6px 0 0;color:var(--muted);line-height:1.5}.notice{background:#fff7df;border:1px solid #ecd596;border-radius:13px;padding:12px 16px;margin:0 0 22px;line-height:1.45}.workspace{display:grid;grid-template-columns:minmax(300px,1.05fr) minmax(340px,1.4fr) minmax(235px,.75fr);gap:18px;align-items:start}.panel{min-width:0;background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow);padding:22px}.panel-head{display:flex;align-items:flex-start;gap:12px;margin-bottom:22px}.step{display:grid;place-items:center;flex:none;width:37px;height:37px;background:#ddf1ee;color:var(--teal-dark);border-radius:11px;font-size:.8rem;font-weight:850}.panel-head h2{margin:0;font-size:1.2rem}.panel-head p{margin:4px 0 0;color:var(--muted);font-size:.88rem;line-height:1.4}label{display:block;margin:16px 0 7px;font-size:.88rem;font-weight:750}.optional{font-weight:400;color:var(--muted)}input,select,textarea{width:100%;border:1px solid #bfcfcd;border-radius:10px;background:white;color:var(--ink);padding:11px 12px;font:inherit;line-height:1.4}textarea{resize:vertical}input::placeholder,textarea::placeholder{color:#7a8d92}.input-unit{position:relative}.input-unit input{padding-right:55px}.input-unit span{position:absolute;right:12px;top:12px;color:var(--muted);font-size:.85rem}.hint{color:var(--muted);font-size:.8rem;line-height:1.5;margin:8px 0 14px}button{width:100%;border:0;border-radius:11px;padding:12px 14px;font:inherit;font-weight:750;cursor:pointer;transition:transform .15s,background .15s}button:hover:not(:disabled){transform:translateY(-1px)}button:disabled{opacity:.48;cursor:not-allowed}.primary{background:var(--teal);color:white;margin-top:15px}.primary:hover:not(:disabled){background:var(--teal-dark)}.secondary{background:#e5f2ef;color:var(--teal-dark);margin-top:15px}.secondary:hover:not(:disabled){background:#d3eae5}:is(button,input,textarea,select):focus-visible{outline:3px solid var(--gold);outline-offset:3px}.error{background:#fff1f1;color:var(--danger);border:1px solid #f0c4c8;border-radius:9px;padding:10px;font-size:.86rem;line-height:1.4}.hidden{display:none!important}#results-container{min-height:410px;max-height:65vh;overflow:auto;background:#f9fbf8;border:1px dashed #bdcfca;border-radius:14px;padding:20px}.empty-state{max-width:390px;margin:38px auto;color:var(--muted)}.empty-icon{font-size:36px}.empty-state h3{color:var(--ink);font-size:1.2rem;margin:12px 0}.empty-state ul{padding-left:20px;line-height:2}.blueprint-text{white-space:pre-wrap;overflow-wrap:anywhere;line-height:1.65;font-size:.93rem}.library select{margin-bottom:2px}.loading-overlay{position:fixed;inset:0;z-index:20;background:rgba(9,34,51,.42);display:grid;place-items:center;padding:16px}.loading-card{display:flex;flex-direction:column;align-items:center;gap:11px;text-align:center;background:var(--paper);border-radius:18px;padding:32px;box-shadow:var(--shadow);max-width:340px}.loading-card span:last-child{color:var(--muted);font-size:.85rem}.spinner{width:38px;height:38px;border:4px solid #d8e7e4;border-top-color:var(--teal);border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}@media(max-width:1200px){.workspace{grid-template-columns:minmax(300px,1fr) minmax(360px,1.3fr)}.library{grid-column:1/-1}}@media(max-width:768px){.app-shell{padding:18px 14px 40px}.workspace{grid-template-columns:1fr}.library{grid-column:auto}.panel{padding:18px}#results-container{min-height:320px;max-height:none}.masthead{align-items:flex-start}.brand-mark{width:48px;height:48px;font-size:25px}}
(() => {
const el = id => document.getElementById(id);
const form = el('build-form');
const nameInput = el('build-name');
const goalInput = el('goal');
const budgetInput = el('budget');
const inventoryInput = el('inventory');
const constraintsInput = el('constraints');
const generateBtn = el('generate-btn');
const saveBtn = el('save-btn');
const loadBtn = el('load-btn');
const savedSelect = el('saved-plans');
const errorBox = el('form-error');
const results = el('results-container');
const overlay = el('loading-overlay');
const status = el('status');
const storageKey = 'agentop-build-a-boat-blueprints-v1';
const hints = {'treasure run':'Prioritize a survivable trip toward the treasure.','starter boat':'Keep the design simple and easy to assemble.','multiplayer boat':'Make room for the whole crew.','themed ship':'Balance the theme with a usable hull.','custom':'Describe your boat idea in the constraints field.'};
let ready = false;
let busy = false;
let draft = null;
let library = {};
const escapeHtml = value => String(value).replace(/[&<>"']/g, char => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[char]));
const isLocal = () => /local|wllama/.test(String(window.PROVIDER || '').toLowerCase()) || !!window.agentManager;
const modelLoaded = () => !isLocal() || !!(window.agentManager && window.agentManager.isLoaded);
function showError(message) { errorBox.textContent = message; errorBox.classList.remove('hidden'); }
function clearError() { errorBox.textContent = ''; errorBox.classList.add('hidden'); }
function updateControls() {
generateBtn.disabled = busy || !ready || !modelLoaded();
saveBtn.disabled = busy || !draft;
loadBtn.disabled = busy || !savedSelect.value || !Object.prototype.hasOwnProperty.call(library, savedSelect.value);
status.textContent = !ready ? 'Initializing blueprint desk…' : busy ? 'Drafting your boat blueprint…' : !modelLoaded() ? 'Load a model from the top bar to draft a blueprint.' : 'Ready to plan your next boat.';
}
function invalidateDraft() { draft = null; updateControls(); }
function renderBlueprint(text) { results.innerHTML = '<div class="blueprint-text">' + escapeHtml(text) + '</div>'; }
function refreshLibrary() {
const selected = savedSelect.value;
savedSelect.innerHTML = '<option value="">Select a browser blueprint</option>';
Object.keys(library).sort((a,b) => a.localeCompare(b)).forEach(key => {
const option = document.createElement('option');
option.value = key;
option.textContent = library[key].name;
savedSelect.appendChild(option);
});
if (Object.prototype.hasOwnProperty.call(library, selected)) savedSelect.value = selected;
updateControls();
}
function readLibrary() {
try {
const data = JSON.parse(localStorage.getItem(storageKey) || '{}');
library = data && typeof data === 'object' && !Array.isArray(data) ? data : {};
} catch (error) { library = {}; showError('Browser blueprints could not be read. Existing data has not been changed.'); }
refreshLibrary();
}
function markReady() { ready = !!window.pyodide; updateControls(); }
document.addEventListener('pyodide-ready', markReady);
if (window.pyodideReady && window.pyodide) markReady();
goalInput.addEventListener('change', () => { el('goal-hint').textContent = hints[goalInput.value] || hints.custom; invalidateDraft(); });
form.addEventListener('input', () => { clearError(); invalidateDraft(); });
form.addEventListener('change', () => { clearError(); invalidateDraft(); });
savedSelect.addEventListener('change', updateControls);
form.addEventListener('submit', async event => {
event.preventDefault();
clearError();
const name = nameInput.value.trim();
const goal = goalInput.value;
const rawBudget = budgetInput.value.trim();
const inventory = inventoryInput.value.trim();
const constraints = constraintsInput.value.trim();
if (!name) return showError('Give your new boat blueprint a name.');
if (!rawBudget || !/^\d+$/.test(rawBudget) || Number(rawBudget) > 1000000) return showError('Enter a whole-number gold limit from 0 to 1,000,000.');
if (!ready || !window.pyodide) return showError('The blueprint desk is still initializing. Try again in a moment.');
if (!modelLoaded()) return showError('Load a model from the top bar before drafting a boat blueprint.');
const request = {name, goal, budget:Number(rawBudget), inventory, constraints};
busy = true; draft = null; updateControls(); overlay.classList.remove('hidden');
try {
window.pyodide.globals.set('user_query', JSON.stringify(request));
const answer = await window.pyodide.runPythonAsync('await process_user_query(user_query)');
if (!String(answer || '').trim()) throw new Error('The blueprint came back empty. Please try again.');
renderBlueprint(String(answer));
draft = {name, request, result:String(answer)};
} catch (error) {
showError('Could not draft the boat blueprint. Check that your model or provider is ready, then try again. ' + (error && error.message ? error.message : ''));
} finally { busy = false; overlay.classList.add('hidden'); updateControls(); }
});
saveBtn.addEventListener('click', () => {
clearError();
if (!draft) return showError('Draft a boat blueprint before saving it.');
const key = draft.name.trim().toLocaleLowerCase();
if (Object.keys(library).some(existing => existing.toLocaleLowerCase() === key)) return showError('A browser blueprint already has that name. Rename this blueprint and draft it again; nothing was overwritten.');
const updated = {...library, [key]:draft};
try { localStorage.setItem(storageKey, JSON.stringify(updated)); library = updated; refreshLibrary(); savedSelect.value = key; draft = null; updateControls(); status.textContent = 'Blueprint saved in this browser. Roblox saves are unchanged.'; }
catch (error) { showError('This browser could not save the blueprint. No existing blueprint was changed.'); }
});
loadBtn.addEventListener('click', () => {
clearError();
const plan = library[savedSelect.value];
if (!plan || !plan.request || typeof plan.result !== 'string') return showError('Choose a valid saved browser blueprint to load.');
nameInput.value = plan.request.name || plan.name || '';
goalInput.value = plan.request.goal || 'custom';
budgetInput.value = Number.isFinite(plan.request.budget) ? plan.request.budget : 0;
inventoryInput.value = plan.request.inventory || '';
constraintsInput.value = plan.request.constraints || '';
el('goal-hint').textContent = hints[goalInput.value] || hints.custom;
renderBlueprint(plan.result);
draft = null;
updateControls();
status.textContent = 'Browser blueprint loaded. No Roblox build or save slot was changed.';
});
readLibrary();
updateControls();
})();
import json
async def process_user_query(query: str) -> str:
"""Draft a Build A Boat for Treasure blueprint without changing game saves.
Args:
query: JSON with blueprint name, goal, gold budget, inventory, and constraints.
"""
try:
data = json.loads(query)
if not isinstance(data, dict):
return 'Please enter a boat blueprint request.'
name = str(data.get('name', '')).strip()[:70]
goal = str(data.get('goal', '')).strip()[:60]
inventory = str(data.get('inventory', '')).strip()[:2500]
constraints = str(data.get('constraints', '')).strip()[:1200]
budget = data.get('budget')
if not name or not isinstance(budget, int) or isinstance(budget, bool) or not 0 <= budget <= 1000000:
return 'Please provide a blueprint name and a whole-number gold budget from 0 to 1,000,000.'
if goal not in ('treasure run', 'starter boat', 'multiplayer boat', 'themed ship', 'custom'):
return 'Please choose a valid boat build goal.'
except (ValueError, TypeError):
return 'Please check the boat blueprint inputs and try again.'
prompt = (
'Draft a practical Build A Boat for Treasure planning blueprint from these inputs:\n'
+ json.dumps({'name': name, 'goal': goal, 'maximum_gold_to_spend': budget,
'owned_parts': inventory or 'Not provided',
'preferences': constraints or 'None'}, ensure_ascii=False)
+ '\nGive short sections: Build concept; Parts to use (mark unknown inventory as optional); '
'Assembly steps; Gold plan; Test and save-safety checklist. '
'Keep purchase suggestions within the stated budget. If current prices or owned parts are '
'unknown, do not invent exact prices, totals, or availability; say what to check in-game. '
'A zero budget means suggest no purchases. Advise using a free/unused in-game save slot '
'and checking its contents before saving; never suggest overwriting an existing build. '
'You cannot access Roblox, place blocks, load in-game saves, or spend gold yourself. '
'Do not imply any of these actions happened. Keep the answer under 450 words.'
)
return str(await agentop_llm.generate(prompt, globals().get('TEMPLATE_SYSTEM_PROMPT', '')))
Name your agent
Based on . You'll get your own private copy to try and customize.