Skip to content

Commit a3a6f9c

Browse files
committed
feat: add a New button that clears the editor for pasting LLM output
The core playground loop is copy LLM prompt, ask an AI for a movement, paste the result. Until now pasting meant hand-selecting and overwriting a preset. A topbar New button clears the editor into a proper paste target: the movement label switches to "New movement", CodeMirror shows a paste-here placeholder while the doc is empty, and the status row shows a hint instead of parse errors. On phones it also switches to the editor pane and focuses it.
1 parent 9dcc3ab commit a3a6f9c

4 files changed

Lines changed: 47 additions & 3 deletions

File tree

playground/play.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@
5555
<span class="lib-caret" aria-hidden="true"></span>
5656
</button>
5757
<span class="tb-divider" aria-hidden="true"></span>
58+
<button
59+
id="new-doc"
60+
class="btn ghost"
61+
aria-label="New movement"
62+
title="Clear the editor so you can paste a movement from your AI chat"
63+
>
64+
<span class="ico-plus" aria-hidden="true"></span><span class="lbl">New</span>
65+
</button>
5866
<button id="how-to" class="btn ghost" aria-label="How to use">
5967
<span class="ico-help" aria-hidden="true"></span><span class="lbl">How to use</span>
6068
</button>

playground/src/editor.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
highlightActiveLineGutter,
1515
drawSelection,
1616
hoverTooltip,
17+
placeholder,
1718
Decoration,
1819
type DecorationSet,
1920
} from "@codemirror/view";
@@ -334,6 +335,10 @@ export function createPosecodeEditor(
334335
lintGutter(),
335336
posecodeHoverTip,
336337
posecodeTheme,
338+
// Shown only while the document is empty: guides the paste-from-LLM flow.
339+
placeholder(
340+
'Paste a movement from your AI chat here, or start typing:\nposecode exercise "My movement"',
341+
),
337342
EditorView.lineWrapping,
338343
keymap.of([
339344
...closeBracketsKeymap,

playground/src/main.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,17 @@ function scheduleRecompile(): void {
148148

149149
function recompile(): void {
150150
window.clearTimeout(debounce); // cancel any pending run; we're compiling now
151-
const { ir, errors, warnings: warns } = parse(editorApi.getValue());
151+
const source = editorApi.getValue();
152+
if (!source.trim()) {
153+
// A deliberately blank editor (the "New" flow): a paste target, not an
154+
// error state. Show a hint instead of parse errors and stop the playback.
155+
warnings.innerHTML =
156+
'<div class="row hint">Blank editor. Paste a movement from your AI chat, or pick one from the library.</div>';
157+
viewer.pause();
158+
setPlaying(false);
159+
return;
160+
}
161+
const { ir, errors, warnings: warns } = parse(source);
152162
renderWarnings(warnings, errors, warns);
153163
if (ir) {
154164
viewer.load(ir);
@@ -318,6 +328,19 @@ libSearch.addEventListener("input", () => {
318328
renderLibraryFilters();
319329
renderLibraryList();
320330

331+
// --- New movement: clear the editor into a paste target for LLM output ---
332+
// The core loop is "Copy LLM prompt → ask an AI for a movement → paste it
333+
// back"; without this, pasting meant overwriting a preset by hand-selecting
334+
// its text first.
335+
$<HTMLButtonElement>("new-doc").addEventListener("click", () => {
336+
currentPresetId = null;
337+
libCurrent.textContent = "New movement";
338+
editorApi.setValue("");
339+
recompile(); // swaps the status row to the blank-editor hint immediately
340+
setMobileView("editor"); // the paste target, front and center on phones
341+
editorApi.focus();
342+
});
343+
321344
// --- Mobile Editor/Viewer toggle (no-op visually on desktop, where both show) ---
322345
function setMobileView(view: "editor" | "viewer"): void {
323346
document.body.dataset.mview = view;

playground/src/style.css

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,8 @@ body {
154154
}
155155

156156
.btn .ico-link,
157-
.btn .ico-help {
157+
.btn .ico-help,
158+
.btn .ico-plus {
158159
width: 14px;
159160
height: 14px;
160161
background: currentColor;
@@ -163,9 +164,13 @@ body {
163164
mask: center / contain no-repeat var(--btn-icon);
164165
}
165166
.btn:hover .ico-link,
166-
.btn:hover .ico-help {
167+
.btn:hover .ico-help,
168+
.btn:hover .ico-plus {
167169
opacity: 1;
168170
}
171+
.btn .ico-plus {
172+
--btn-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='12' y1='5' x2='12' y2='19'/%3E%3Cline x1='5' y1='12' x2='19' y2='12'/%3E%3C/svg%3E");
173+
}
169174
.btn .ico-link {
170175
--btn-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10 13a5 5 0 0 0 7.07 0l3-3a5 5 0 0 0-7.07-7.07l-1.5 1.5'/%3E%3Cpath d='M14 11a5 5 0 0 0-7.07 0l-3 3a5 5 0 0 0 7.07 7.07l1.5-1.5'/%3E%3C/svg%3E");
171176
}
@@ -529,6 +534,9 @@ select:hover {
529534
.warnings .warn {
530535
color: var(--warn);
531536
}
537+
.warnings .hint {
538+
color: var(--muted);
539+
}
532540

533541
/* --- Viewer pane ---------------------------------------------------------- */
534542
.viewer-pane {

0 commit comments

Comments
 (0)