maze-blockly-wrapper 0.7.6 → 0.7.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -131,16 +131,72 @@ interface MazeConfig {
131
131
  ```
132
132
 
133
133
  ### RunResult
134
+ Each game component returns a result object via the `onRunFinish` callback when specific conditions are met.
134
135
 
136
+ #### MazeGame Result
137
+ **When sent:** Triggered when the spider reaches the finish line OR when maximum moves are exceeded.
135
138
  ```typescript
136
139
  interface RunResult {
137
- steps: number;
138
- reachedFinish: boolean;
139
- maxMovesExceeded: boolean;
140
- finalPosition: Position;
141
- path: Position[];
142
- executionTime: number;
143
- error?: string;
140
+ steps: number; // Number of steps taken
141
+ reachedFinish: boolean; // True if spider reached the finish cell
142
+ maxMovesExceeded: boolean; // True if maxMoves limit was hit
143
+ finalPosition: Position; // Where the spider ended up
144
+ path: Position[]; // Array of positions visited (todo)
145
+ executionTime: number; // Time in ms (todo)
146
+ inventory: string[]; // Collected items (COIN, KEY, etc.)
147
+ }
148
+ ```
149
+
150
+ #### FilmGame Result
151
+ **When sent:** Triggered when the user clicks the "Finish" button to check their movie against the target.
152
+ ```typescript
153
+ interface RunResult {
154
+ commands: number; // Total drawing commands used
155
+ reachedTarget: boolean; // True if accuracy > 80%
156
+ maxCommandsExceeded: boolean;
157
+ shapes: Shape[]; // Array of shapes drawn by student
158
+ executionTime: number; // Time in ms
159
+ accuracy: number; // 0-1 score representing similarity to target
160
+ tickCount: number; // Final tick count
161
+ comparisonResult: { // Detailed breakdown
162
+ shapeCountMatch: boolean;
163
+ shapeTypesMatch: boolean;
164
+ positionAccuracy: number;
165
+ sizeAccuracy: number;
166
+ colorAccuracy: number;
167
+ };
168
+ }
169
+ ```
170
+
171
+ #### DrawingGame Result
172
+ **When sent:** Triggered automatically when code execution completes.
173
+ ```typescript
174
+ interface RunResult {
175
+ commands: number; // Total commands executed
176
+ reachedTarget: boolean; // True if game state marked as won (custom logic)
177
+ maxCommandsExceeded: boolean;
178
+ finalPosition: Position; // Final pen position
179
+ drawnPath: Position[]; // Array of points visited by pen
180
+ executionTime: number; // Time in ms
181
+ accuracy: number; // 0-1 score comparing drawn path to target path
182
+ }
183
+ ```
184
+
185
+ #### MusicGame Result
186
+ **When sent:** Triggered automatically when the music finishes playing.
187
+ ```typescript
188
+ interface RunResult {
189
+ commands: number; // Total notes/pauses played
190
+ reachedTarget: boolean; // True if accuracy is 100%
191
+ maxCommandsExceeded: boolean;
192
+ notes: Note[]; // Array of notes played
193
+ executionTime: number; // Playback time in ms
194
+ accuracy: number; // 0-100 score comparing played notes to editor notes
195
+ comparisonResult: {
196
+ noteCountMatch: boolean;
197
+ melodyAccuracy: number; // Pitch/Duration match score
198
+ rhythmAccuracy: number; // Timing match score
199
+ };
144
200
  }
145
201
  ```
146
202
 
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ declare const MusicDemo: React.FC;
3
+ export default MusicDemo;
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ interface GameControlsProps {
3
+ isPlaying: boolean;
4
+ isPaused: boolean;
5
+ onPlay: () => void;
6
+ onPause: () => void;
7
+ onStop: () => void;
8
+ onReset: () => void;
9
+ }
10
+ declare const GameControls: React.FC<GameControlsProps>;
11
+ export default GameControls;
@@ -0,0 +1,41 @@
1
+ import { Component } from 'react';
2
+ import type { InstrumentType, MusicBlocklyConfig, NoteDuration, NoteName, NoteOctave } from './types';
3
+ interface MusicBlocklyContainerProps {
4
+ config: MusicBlocklyConfig;
5
+ onWorkspaceChange: (code: string) => void;
6
+ className?: string;
7
+ onPreloadInstruments?: (instruments: InstrumentType[]) => Promise<void>;
8
+ }
9
+ interface MusicBlocklyContainerState {
10
+ initialized: boolean;
11
+ error: string | null;
12
+ showNoteDialog: boolean;
13
+ noteDialogValues: {
14
+ note: NoteName;
15
+ octave: NoteOctave;
16
+ duration: NoteDuration;
17
+ };
18
+ activeField: any | null;
19
+ }
20
+ declare class MusicBlocklyContainer extends Component<MusicBlocklyContainerProps, MusicBlocklyContainerState> {
21
+ private blocklyDiv;
22
+ private workspace;
23
+ private updateTimeout;
24
+ constructor(props: MusicBlocklyContainerProps);
25
+ componentDidMount(): void;
26
+ componentDidUpdate(prevProps: MusicBlocklyContainerProps): void;
27
+ componentWillUnmount(): void;
28
+ /**
29
+ * Preload common instruments when Blockly container is ready
30
+ */
31
+ private preloadInstruments;
32
+ private initializeBlockly;
33
+ private generateCode;
34
+ private registerGenerators;
35
+ getWorkspace(): any;
36
+ private handleOpenNoteEditor;
37
+ private handleNoteSave;
38
+ private handleNoteClose;
39
+ render(): JSX.Element;
40
+ }
41
+ export default MusicBlocklyContainer;
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import { type GraphicsConfig, type Note, type Pause } from './types';
3
+ interface MusicCanvasProps {
4
+ width: number;
5
+ height: number;
6
+ notes: (Note | Pause)[];
7
+ currentBeat: number;
8
+ isPlaying: boolean;
9
+ selectedRows: number;
10
+ graphicsConfig: GraphicsConfig;
11
+ editorNotes?: (Note | Pause)[];
12
+ }
13
+ declare const MusicCanvas: React.FC<MusicCanvasProps>;
14
+ export default MusicCanvas;
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import type { MusicBlocklyConfig } from './types';
3
+ interface MusicEditorProps {
4
+ config: MusicBlocklyConfig;
5
+ onWorkspaceChange: (code: string) => void;
6
+ tempo: number;
7
+ onTempoChange: (tempo: number) => void;
8
+ blocklyRef?: React.RefObject<any>;
9
+ }
10
+ declare const MusicEditor: React.FC<MusicEditorProps>;
11
+ export default MusicEditor;
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import { type WithTranslation } from 'react-i18next';
3
+ import { type GraphicsConfig, type MusicConfig, type RunResult } from './types';
4
+ interface MusicGameProps extends WithTranslation {
5
+ className?: string;
6
+ isEditable?: boolean;
7
+ configuration?: MusicConfig;
8
+ onChange?: (config: MusicConfig) => void;
9
+ onRunFinish?: (result: RunResult) => void;
10
+ maxCommands?: number;
11
+ showControls?: boolean;
12
+ graphicsConfig?: Partial<GraphicsConfig>;
13
+ }
14
+ declare const MusicGameWithTranslation: React.ComponentType<Omit<MusicGameProps, keyof WithTranslation>>;
15
+ export default MusicGameWithTranslation;
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import type { GraphicsConfig, InstrumentType, MusicBlocklyConfig, MusicConfig, MusicState, Note, Pause } from './types';
3
+ interface MusicTabsProps {
4
+ musicConfig: MusicConfig;
5
+ gameState: MusicState;
6
+ editorState: MusicState;
7
+ generatedCode: string;
8
+ blocklyConfig: MusicBlocklyConfig;
9
+ onConfigChange: (config: MusicConfig) => void;
10
+ onCodeChange: (code: string) => void;
11
+ onEditorStateChange: (state: Partial<MusicState>) => void;
12
+ onEditorNotesChange?: (notes: (Note | Pause)[]) => void;
13
+ graphicsConfig: GraphicsConfig;
14
+ className?: string;
15
+ blocklyRef?: React.RefObject<any>;
16
+ editorBlocklyRef?: React.RefObject<any>;
17
+ editorNotes?: (Note | Pause)[];
18
+ onPreloadInstruments?: (instruments: InstrumentType[]) => Promise<void>;
19
+ }
20
+ declare const MusicTabs: React.FC<MusicTabsProps>;
21
+ export default MusicTabs;
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import { type GraphicsConfig, type InstrumentType, type Note, type Pause } from './types';
3
+ interface MusicVisualEditorProps {
4
+ tempo: number;
5
+ onTempoChange: (tempo: number) => void;
6
+ selectedRows: number;
7
+ onSelectedRowsChange: (rows: number) => void;
8
+ onCodeChange: (code: string) => void;
9
+ onNotesChange?: (notes: (Note | Pause)[]) => void;
10
+ graphicsConfig: GraphicsConfig;
11
+ onPreloadInstruments?: (instruments: InstrumentType[]) => Promise<void>;
12
+ }
13
+ declare const MusicVisualEditor: React.FC<MusicVisualEditorProps>;
14
+ export default MusicVisualEditor;
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import type { NoteDuration, NoteName, NoteOctave } from './types';
3
+ interface NoteDialogProps {
4
+ show: boolean;
5
+ onClose: () => void;
6
+ onSave: (note: NoteName, octave: NoteOctave, duration: NoteDuration) => void;
7
+ initialValues: {
8
+ note: NoteName;
9
+ octave: NoteOctave;
10
+ duration: NoteDuration;
11
+ };
12
+ }
13
+ declare const NoteDialog: React.FC<NoteDialogProps>;
14
+ export default NoteDialog;
@@ -0,0 +1,54 @@
1
+ import { type InstrumentType, type Note, type NoteDuration, type NoteOctave } from './types';
2
+ /**
3
+ * Audio engine for playing musical notes using real instrument samples (SoundFont)
4
+ */
5
+ export declare class AudioEngine {
6
+ private audioContext;
7
+ private masterGain;
8
+ private activeNotes;
9
+ private loadedInstruments;
10
+ private loadingInstruments;
11
+ private readonly instrumentMap;
12
+ constructor();
13
+ private initAudioContext;
14
+ /**
15
+ * Pre-load one or more instruments (public method for proactive loading)
16
+ */
17
+ preloadInstruments(instrumentTypes: InstrumentType[]): Promise<void>;
18
+ /**
19
+ * Load an instrument SoundFont (lazy loading)
20
+ */
21
+ private loadInstrument;
22
+ /**
23
+ * Play a single note using SoundFont samples
24
+ */
25
+ playNote(note: Note, tempo: number, instrument?: InstrumentType, onComplete?: () => void): Promise<void>;
26
+ /**
27
+ * Convert note name and octave to SoundFont format (e.g., "C4", "D#5")
28
+ */
29
+ private getNoteNameForSoundfont;
30
+ /**
31
+ * Fallback: Play note using oscillator (for drums or when SoundFont fails)
32
+ */
33
+ private playNoteWithOscillator;
34
+ /**
35
+ * Configure oscillator and gain based on instrument type with better synthesis
36
+ */
37
+ private configureInstrument;
38
+ /**
39
+ * Play a keyboard key (for interactive playing)
40
+ */
41
+ playKeyboardNote(noteName: string, octave: NoteOctave, duration?: NoteDuration, instrument?: InstrumentType): void;
42
+ /**
43
+ * Stop all playing notes
44
+ */
45
+ stopAll(): void;
46
+ /**
47
+ * Resume audio context (needed for browsers that suspend it)
48
+ */
49
+ resume(): Promise<void>;
50
+ /**
51
+ * Cleanup and close audio context
52
+ */
53
+ dispose(): void;
54
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Load music-specific Blockly messages
3
+ * This should be called before registerMusicBlocks()
4
+ */
5
+ export declare function loadMusicBlocklyMessages(): void;
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Register music blocks with Blockly
3
+ */
4
+ export declare function registerMusicBlocks(): void;
@@ -0,0 +1,2 @@
1
+ export declare function getFieldMusicNoteClass(): any;
2
+ export declare function registerFieldMusicNote(): void;
@@ -0,0 +1,3 @@
1
+ import type { GraphicsConfig } from './types';
2
+ export declare const defaultGraphicsConfig: GraphicsConfig;
3
+ export declare function mergeGraphicsConfig(userConfig?: Partial<GraphicsConfig>): GraphicsConfig;
@@ -0,0 +1,12 @@
1
+ export { default as MusicGame } from './MusicGame';
2
+ export { default as MusicCanvas } from './MusicCanvas';
3
+ export { default as MusicEditor } from './MusicEditor';
4
+ export { default as MusicVisualEditor } from './MusicVisualEditor';
5
+ export { default as MusicTabs } from './MusicTabs';
6
+ export { default as GameControls } from './GameControls';
7
+ export { default as MusicBlocklyContainer } from './MusicBlocklyContainer';
8
+ export * from './types';
9
+ export * from './blocks';
10
+ export * from './blockly-messages';
11
+ export * from './graphicsConfig';
12
+ export * from './audioEngine';
@@ -0,0 +1,76 @@
1
+ export type NoteDuration = 'whole' | 'half' | 'quarter' | 'eighth' | 'sixteenth';
2
+ export type NoteName = 'C' | 'D' | 'E' | 'F' | 'G' | 'A' | 'B';
3
+ export type NoteOctave = 1 | 2 | 3 | 4 | 5;
4
+ export type InstrumentType = 'piano' | 'guitar' | 'acoustic_guitar' | 'electric_guitar' | 'bass' | 'drums' | 'flute' | 'violin' | 'saxophone';
5
+ export interface Note {
6
+ id: string;
7
+ name: NoteName;
8
+ octave: NoteOctave;
9
+ duration: NoteDuration;
10
+ row: number;
11
+ startBeat: number;
12
+ instrument?: InstrumentType;
13
+ }
14
+ export interface Pause {
15
+ id: string;
16
+ duration: NoteDuration;
17
+ row: number;
18
+ startBeat: number;
19
+ }
20
+ export type MusicCommand = Note | Pause;
21
+ export interface MusicState {
22
+ isPlaying: boolean;
23
+ isPaused: boolean;
24
+ currentBeat: number;
25
+ commands: MusicCommand[];
26
+ commandCount: number;
27
+ maxCommands: number;
28
+ selectedRows: number;
29
+ instrument: InstrumentType;
30
+ tempo: number;
31
+ }
32
+ export interface MusicConfig {
33
+ targetNotes: Note[];
34
+ maxCommands: number;
35
+ selectedRows: number;
36
+ tempo: number;
37
+ instrument: InstrumentType;
38
+ }
39
+ export interface MusicBlocklyConfig {
40
+ allowedTypes: Set<string>;
41
+ limits: Record<string, number>;
42
+ toolbox: string;
43
+ initialXml: string;
44
+ }
45
+ export interface RunResult {
46
+ commands: number;
47
+ reachedTarget: boolean;
48
+ maxCommandsExceeded: boolean;
49
+ notes: Note[];
50
+ executionTime: number;
51
+ accuracy: number;
52
+ comparisonResult?: {
53
+ noteCountMatch: boolean;
54
+ melodyAccuracy: number;
55
+ rhythmAccuracy: number;
56
+ };
57
+ }
58
+ export interface GraphicsConfig {
59
+ canvas: {
60
+ backgroundColor: string;
61
+ borderColor: string;
62
+ borderWidth: number;
63
+ };
64
+ staff: {
65
+ lineColor: string;
66
+ lineWidth: number;
67
+ spacing: number;
68
+ };
69
+ notes: {
70
+ fillColor: string;
71
+ strokeColor: string;
72
+ strokeWidth: number;
73
+ };
74
+ }
75
+ export declare const DURATION_TO_BEATS: Record<NoteDuration, number>;
76
+ export declare function getNoteFrequency(note: NoteName, octave: NoteOctave): number;