Upgrade Project

This commit is contained in:
Chad Freeman 2025-01-12 12:56:21 -05:00
parent ea65bf0ecd
commit d69737050a
21 changed files with 331 additions and 189 deletions

4
.gitignore vendored
View file

@ -3,6 +3,8 @@ node_modules
# Output # Output
.output .output
.vercel .vercel
.netlify
.wrangler
/.svelte-kit /.svelte-kit
/build /build
@ -19,3 +21,5 @@ Thumbs.db
# Vite # Vite
vite.config.js.timestamp-* vite.config.js.timestamp-*
vite.config.ts.timestamp-* vite.config.ts.timestamp-*
old/

View file

@ -3,7 +3,7 @@
"singleQuote": true, "singleQuote": true,
"trailingComma": "none", "trailingComma": "none",
"printWidth": 100, "printWidth": 100,
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"], "plugins": ["prettier-plugin-svelte"],
"overrides": [ "overrides": [
{ {
"files": "*.svelte", "files": "*.svelte",

View file

@ -1,16 +1,38 @@
# Sprigsy editor # sv
# planned for v1 Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
- [ ] ability to play project
- [ ] monaco code editor
- [ ] export project for sprig
- [ ] docs site
- [ ] typescript support (esbuild prob)
## Creating a project
# planned for v2 If you're seeing this, you've probably already done this step. Congrats!
- [ ] sprite manager
- [ ] level manager ```bash
- [ ] build project as a standalone `.html` file # create a new project in the current directory
- [ ] run on device npx sv create
- [ ] downloadable version
# create a new project in my-app
npx sv create my-app
```
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
## Building
To create a production version of your app:
```bash
npm run build
```
You can preview the production build with `npm run preview`.
> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.

BIN
bun.lockb

Binary file not shown.

View file

@ -1,37 +1,35 @@
{ {
"name": "sprigsy", "name": "sprig-editor",
"version": "0.0.1",
"private": true, "private": true,
"version": "0.0.1",
"type": "module",
"scripts": { "scripts": {
"dev": "vite dev", "dev": "vite dev",
"build": "vite build", "build": "vite build",
"preview": "vite preview", "preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check .", "format": "prettier --write .",
"format": "prettier --write ." "lint": "prettier --check ."
}, },
"devDependencies": { "devDependencies": {
"@sveltejs/adapter-auto": "^3.0.0", "@babel/parser": "^7.26.5",
"@sveltejs/adapter-static": "^3.0.6",
"@sveltejs/kit": "^2.0.0", "@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0", "@sveltejs/vite-plugin-svelte": "^4.0.0",
"@tailwindcss/typography": "^0.5.14", "@tailwindcss/postcss": "^4.0.0-beta.9",
"autoprefixer": "^10.4.20", "babel-walk": "^3.0.1",
"babel-walk": "^3.0.0",
"prettier": "^3.1.1",
"prettier-plugin-svelte": "^3.1.2",
"prettier-plugin-tailwindcss": "^0.6.5",
"svelte": "^5.0.0-next.1",
"svelte-check": "^3.6.0",
"tailwindcss": "^3.4.9",
"typescript": "^5.0.0",
"vite": "^5.0.3",
"@babel/parser": "^7.25.3",
"@sveltejs/adapter-static": "^3.0.4",
"constrained-editor-plugin": "^1.3.0", "constrained-editor-plugin": "^1.3.0",
"monaco-editor": "^0.50.0", "daisyui": "^5.0.0-beta.1",
"esbuild-wasm": "^0.24.2",
"monaco-editor": "^0.52.2",
"prettier": "^3.3.2",
"prettier-plugin-svelte": "^3.2.6",
"sprig": "^1.1.3", "sprig": "^1.1.3",
"sveltekit-adapter-deno": "^0.12.1" "svelte": "^5.0.0",
}, "svelte-check": "^4.0.0",
"type": "module" "tailwindcss": "^4.0.0-beta.9",
"typescript": "^5.0.0",
"vite": "^5.4.11"
}
} }

View file

@ -1,6 +1,5 @@
export default { export default {
plugins: { plugins: {
tailwindcss: {}, '@tailwindcss/postcss': {},
autoprefixer: {}
} }
}; };

View file

@ -1,7 +1,21 @@
@import 'tailwindcss/base'; @import 'tailwindcss';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities';
body, html { @plugin 'daisyui';
/*
The default border color has changed to `currentColor` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still
looks the same as it did with Tailwind CSS v3.
If we ever want to remove these styles, we need to add an explicit border
color utility to any element that depends on these defaults.
*/
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentColor);
}
} }

2
src/app.d.ts vendored
View file

@ -1,4 +1,4 @@
// See https://kit.svelte.dev/docs/types#app // See https://svelte.dev/docs/kit/types#app.d.ts
// for information about these interfaces // for information about these interfaces
declare global { declare global {
namespace App { namespace App {

View file

@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" /> <link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head% %sveltekit.head%
</head> </head>
<body data-sveltekit-preload-data="hover"> <body data-sveltekit-preload-data="hover">

View file

@ -1,10 +1,11 @@
<script lang="ts"> <script lang=ts>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import * as monaco from 'monaco-editor'; import * as monaco from 'monaco-editor';
import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'; import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker';
import {} from 'sprig/web'; import {} from 'sprig/web';
import { constrainedEditor } from 'constrained-editor-plugin'; import { constrainedEditor } from 'constrained-editor-plugin';
import { parse } from '@babel/parser'; import { parse } from '@babel/parser';
import { buildProject } from './build';
let editorContainer: HTMLDivElement; let editorContainer: HTMLDivElement;
let editor: import('monaco-editor').editor.IStandaloneCodeEditor; let editor: import('monaco-editor').editor.IStandaloneCodeEditor;
@ -19,8 +20,9 @@
}, timeout); }, timeout);
}; };
} }
let code = `console.log('Hello sprig!');`; let { code = $bindable() }: { code: string } = $props();
onMount(async () => { onMount(async () => {
window.build = () => buildProject(code, true);
globalThis.process = {}; globalThis.process = {};
globalThis.process.env = {}; globalThis.process.env = {};
const { recursive } = await import('babel-walk'); const { recursive } = await import('babel-walk');
@ -38,11 +40,6 @@
sprigTypeDef, sprigTypeDef,
'context/sprig.d.ts' 'context/sprig.d.ts'
); );
const globalTypeDef = (await import('./editorcontext/global.d.ts?raw')).default;
monaco.languages.typescript.typescriptDefaults.addExtraLib(
globalTypeDef,
'global.d.ts'
);
// IMPLEMENT ONCE v2 IS DONE! // IMPLEMENT ONCE v2 IS DONE!
// const sprigsyTypeDef = (await import('./editorcontext/sprigsy.d.ts?raw')).default; // const sprigsyTypeDef = (await import('./editorcontext/sprigsy.d.ts?raw')).default;
@ -54,10 +51,10 @@
const disallowedIdentifiers = ['window', 'globalThis']; const disallowedIdentifiers = ['window', 'globalThis'];
type ASTState = { type ASTState = {
disallowedWarnings: { identifier: string; loc: [number, number, number, number] }[]; disallowedWarnings: { identifier: string; loc: [number, number, number, number] }[];
errors: { reason: string; loc: [number, number, number, number] }[];
}; };
const ASTWalker = recursive<ASTState>({ const ASTWalker = recursive<ASTState>({
Identifier(node, state, c) { Identifier(node, state, c) {
console;
if (disallowedIdentifiers.includes(node.name)) { if (disallowedIdentifiers.includes(node.name)) {
state.disallowedWarnings.push({ state.disallowedWarnings.push({
identifier: node.name, identifier: node.name,
@ -69,16 +66,33 @@
] ]
}); });
} }
},
MemberExpression(node, state, c) {
if (node.optional) {
state.errors.push({
reason: 'optional chaining (?.) will work in the editor but it will not work on the sprig console',
loc: [
node.loc?.start.line!,
node.loc?.start.column!,
node.loc?.end.line!,
node.loc?.end.column!
]
});
}
} }
}); });
const checkBabel = debounce(() => { const checkBabel = debounce(() => {
console.log('checking for uhh'); let ast;
const ast = parse(editor.getValue(), { try {
ast = parse(editor.getValue(), {
plugins: ['typescript'] plugins: ['typescript']
}); });
const state: ASTState = { disallowedWarnings: [] }; } catch {
return;
}
const state: ASTState = { disallowedWarnings: [], errors: [] };
ASTWalker(ast, state); ASTWalker(ast, state);
console.log(state);
state.disallowedWarnings.forEach((v) => { state.disallowedWarnings.forEach((v) => {
monaco.editor.setModelMarkers(editor.getModel()!, editor.getId(), [ monaco.editor.setModelMarkers(editor.getModel()!, editor.getId(), [
{ {
@ -95,9 +109,8 @@
function setupEditor() { function setupEditor() {
editor = monaco.editor.create(editorContainer, { editor = monaco.editor.create(editorContainer, {
value: value: `async function game(api: sprig.FullSprigAPI): void {
`function game(api: sprig.FullSprigAPI): void { // Code here
${code}
}`, }`,
language: 'typescript', language: 'typescript',
automaticLayout: true, automaticLayout: true,
@ -110,14 +123,16 @@
constrainedInstance.initializeIn(editor); constrainedInstance.initializeIn(editor);
constrainedInstance.addRestrictionsTo(model, [ constrainedInstance.addRestrictionsTo(model, [
{ {
range: [2, 1, 2, code.length + 2], // Range of Function definition range: [2, 1, 2, 14], // Range of Function definition
allowMultiline: true, allowMultiline: true,
label: 'funcDefinition' label: 'funcDefinition'
} }
]); ]);
model.updateValueInEditableRanges({
funcDefinition: code
});
editor.onDidChangeModelContent((event) => { editor.onDidChangeModelContent((event) => {
console.log(event.changes); code = model.getValueInEditableRanges().funcDefinition;
console.log(model.getValueInEditableRanges());
checkBabel(); checkBabel();
}); });
} }
@ -131,9 +146,8 @@
<div bind:this={editorContainer} class="editor-container"></div> <div bind:this={editorContainer} class="editor-container"></div>
<style> <style lang=postcss>
.editor-container { .editor-container {
height: 100vh; @apply h-screen w-full;
width: 100%;
} }
</style> </style>

23
src/lib/build/index.ts Normal file
View file

@ -0,0 +1,23 @@
import { transform, initialize } from 'esbuild-wasm';
await initialize({
wasmURL: (await import('esbuild-wasm/esbuild.wasm')).default
});
export async function buildProject(code: string, vanilla: boolean) {
let template = '';
if (vanilla) {
template += `function game(api) {
${code}
}
console.log("Made with Sprigsy")
game({ addSprite, addText, afterInput, bitmap, clearInterval, clearText, clearTile, clearTimeout, color, getAll, getFirst, getGrid, getTile, height, map, onInput, playTune, setBackground, setInterval, setLegend, setMap, setPushables, setSolids, setTimeout, tilesWith, tune, width })
`;
} else {
throw new Error('not implemented');
}
return await transform(template, {
loader: 'ts'
});
}

View file

@ -0,0 +1,38 @@
<script lang="ts">
import type { Snippet } from 'svelte';
let {
tab = $bindable(),
disabled = $bindable(false),
map,
...props
}: {
tab: string | undefined;
disabled?: boolean;
map?: Record<string, string>;
class?: string;
[x: `_${string}`]: Snippet<[]>;
} = $props();
const tabs = Object.fromEntries(
Object.entries(props)
.filter((v) => v[0].startsWith('_'))
.map(([name, snippet]): [string, Snippet<[]>] => [name.replace('_', ''), snippet])
);
</script>
<div role="tablist" class="tabs tabs-boxed {props.class}">
{#each Object.entries(tabs) as [tabID]}
<!-- svelte-ignore a11y_interactive_supports_focus -->
<!-- svelte-ignore a11y_click_events_have_key_events -->
<!-- svelte-ignore a11y_missing_attribute -->
<a
class:cursor-not-allowed={disabled}
class:pointer-events-none={disabled}
class:tab-disabled={disabled}
role="tab"
class="tab uppercase"
onclick={() => (tab = tabID)}
class:tab-active={tabID == tab}>{@render tabs[tabID]()}</a
>
{/each}
</div>

View file

@ -1,11 +0,0 @@
// for some reason this doesn't work, I can't figure out why
declare global {
declare function tune(template: TemplateStringsArray, ...params: string[]): string
interface Window {
setTimeout: import('./sprig').sprig.FullSprigAPI['setTimeout'];
setInterval: sprig.FullSprigAPI['setInterval'];
clearTimeout: sprig.FullSprigAPI['clearTimeout'];
clearInterval: sprig.FullSprigAPI['clearInterval'];
}
}

View file

@ -3,8 +3,8 @@
* this is provided because your project type is * this is provided because your project type is
*/ */
declare namespace sprig { declare namespace sprig {
export declare const VALID_INPUTS: readonly ["w", "s", "a", "d", "i", "j", "k", "l"]; export declare const VALID_INPUTS: readonly ['w', 's', 'a', 'd', 'i', 'j', 'k', 'l'];
export type InputKey = typeof VALID_INPUTS[number]; export type InputKey = (typeof VALID_INPUTS)[number];
export interface AddTextOptions { export interface AddTextOptions {
x?: number; x?: number;
y?: number; y?: number;
@ -43,7 +43,7 @@ declare namespace sprig {
} }
// export declare const tones: Record<string, number>; // export declare const tones: Record<string, number>;
// export declare const instruments: readonly ["sine", "triangle", "square", "sawtooth"]; // export declare const instruments: readonly ["sine", "triangle", "square", "sawtooth"];
export type InstrumentType = typeof instruments[number]; export type InstrumentType = (typeof instruments)[number];
// export declare const instrumentKey: Record<string, InstrumentType>; // export declare const instrumentKey: Record<string, InstrumentType>;
// export declare const reverseInstrumentKey: Record<"sine" | "triangle" | "square" | "sawtooth", string>; // export declare const reverseInstrumentKey: Record<"sine" | "triangle" | "square" | "sawtooth", string>;
export type Tune = [number, ...(InstrumentType | number | string)[]][]; export type Tune = [number, ...(InstrumentType | number | string)[]][];
@ -64,7 +64,7 @@ declare namespace sprig {
setPushables(map: Record<string, string[]>): void; setPushables(map: Record<string, string[]>): void;
setBackground(type: string): void; setBackground(type: string): void;
getFirst(type: string): SpriteType | undefined; getFirst(type: string): SpriteType | undefined;
getAll(type: string): SpriteType[]; getAll(type?: string): SpriteType[];
width(): number; width(): number;
height(): number; height(): number;
setLegend(...bitmaps: [string, string][]): void; setLegend(...bitmaps: [string, string][]): void;

View file

@ -3,9 +3,11 @@
* this is provided because your project has sprigsy v2 enabeled * this is provided because your project has sprigsy v2 enabeled
*/ */
declare namespace sprigsy { declare namespace sprigsy {
export interface FullSprigsyAPI {
/** /**
* Retrieve a sprite key for the sprite name * Retrieve a sprite key for the sprite name
* @param name Sprite name * @param name Sprite name
*/ */
function spriteKeyFor(name: string): string spriteKeyFor(name: string): string;
}
} }

View file

@ -1,5 +1,6 @@
<script> <script lang="ts">
import '../app.css'; import '../app.css';
const { children } = $props();
</script> </script>
<slot></slot> {@render children()}

View file

@ -1,2 +1 @@
export const prerender = true; export const csr = true;
export const ssr = false

View file

@ -1,8 +1,58 @@
<script> <script>
import CodeEditor from "$lib/CodeEditor.svelte"; import CodeEditor from '$lib/CodeEditor.svelte';
import Tab from '$lib/components/Tab.svelte';
let tab = 'code';
let code = '';
</script> </script>
<div class="">
<CodeEditor />
<div class="flex h-full! w-full select-none flex-col bg-base-100">
<nav class="flex flex-row">
<Tab bind:tab>
{#snippet _settings()}<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="size-6"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M6 13.5V3.75m0 9.75a1.5 1.5 0 0 1 0 3m0-3a1.5 1.5 0 0 0 0 3m0 3.75V16.5m12-3V3.75m0 9.75a1.5 1.5 0 0 1 0 3m0-3a1.5 1.5 0 0 0 0 3m0 3.75V16.5m-6-9V3.75m0 3.75a1.5 1.5 0 0 1 0 3m0-3a1.5 1.5 0 0 0 0 3m0 9.75V10.5"
/>
</svg>
{/snippet}
{#snippet _code()}Code{/snippet}
{#snippet _test()}Test{/snippet}
{#snippet _tunes()}Tunes{/snippet}
{#snippet _sprites()}Sprites{/snippet}
{#snippet _maps()}Maps{/snippet}
</Tab>
<div class="flex grow items-center justify-end">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="size-6"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M5.25 5.653c0-.856.917-1.398 1.667-.986l11.54 6.347a1.125 1.125 0 0 1 0 1.972l-11.54 6.347a1.125 1.125 0 0 1-1.667-.986V5.653Z"
/>
</svg>
</div>
</nav>
{#if tab === 'code'}
<CodeEditor bind:code />
{:else if ['tunes', 'sprites', 'maps'].includes(tab)}
Not implemented
{:else if tab === 'settings'}
(Settings tab)
{:else if tab === 'test'}
This will have the game screen
{/if}
</div> </div>

View file

@ -3,14 +3,14 @@ import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import('@sveltejs/kit').Config} */ /** @type {import('@sveltejs/kit').Config} */
const config = { const config = {
// Consult https://kit.svelte.dev/docs/integrations#preprocessors // Consult https://svelte.dev/docs/kit/integrations
// for more information about preprocessors // for more information about preprocessors
preprocess: vitePreprocess(), preprocess: vitePreprocess(),
kit: { kit: {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
// If your environment is not supported, or you settled on a specific environment, switch out the adapter. // If your environment is not supported, or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters. // See https://svelte.dev/docs/kit/adapters for more information about adapters.
adapter: adapter() adapter: adapter()
} }
}; };

View file

@ -1,11 +0,0 @@
import type { Config } from 'tailwindcss';
export default {
content: ['./src/**/*.{html,js,svelte,ts}'],
theme: {
extend: {}
},
plugins: [ ]
} as Config;

View file

@ -11,8 +11,8 @@
"strict": true, "strict": true,
"moduleResolution": "bundler" "moduleResolution": "bundler"
} }
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
// except $lib which is handled by https://kit.svelte.dev/docs/configuration#files // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
// //
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
// from the referenced tsconfig.json - TypeScript does not merge them in // from the referenced tsconfig.json - TypeScript does not merge them in