Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
446ba7b
feat: add a 2d sense hat model
G3zz Oct 8, 2026
5799c39
fix: SenseHAT 2D rotations
G3zz Oct 30, 2026
48e974b
chore: fix state copying and improve styling
G3zz Oct 30, 2026
1b148d5
chore: update Simulator2d CSS
G3zz Oct 30, 2026
885d3f5
fix: AstroPiModel tests
G3zz Oct 30, 2026
3a31f25
fix: astro pi cypress tests
G3zz Oct 30, 2026
59c7849
chore: renaming and extracting translations
G3zz Oct 30, 2026
3d02bbf
fix: astro pi cypress tests
G3zz Oct 30, 2026
fd7cdf9
fix: astro pi react tests
G3zz Oct 30, 2026
7cf48db
refactor: extract astro pi inline css
G3zz Nov 2, 2026
eeb351a
fix: missing astro-pi sense hat translation
G3zz Nov 2, 2026
7f57c65
feat: add material zoom_in zoom_out icons
G3zz Nov 5, 2026
3e22f80
chore: add zoom icons to astro pi 2d view
G3zz Nov 5, 2026
df2832a
chore: finalise astro pi 2d view
G3zz Nov 5, 2026
de33c20
Merge remote-tracking branch 'origin/main' into feature/2d-astro-pi-m…
G3zz Nov 5, 2026
e19f09e
fix: linter error in Simulator2d
G3zz Nov 5, 2026
b705167
fix: AstroPiModel styles post-merge
G3zz Nov 5, 2026
bcf9ef3
fix: AstroPi component display order
G3zz Nov 5, 2026
2038d60
fix: linter issues in astro pi css
G3zz Nov 5, 2026
efb30b4
fix: linter issues with astro pi css
G3zz Nov 5, 2026
84bcef3
fix: cypress mz test
G3zz Nov 5, 2026
04993b0
fix: cypress skult test
G3zz Nov 5, 2026
a0e7c94
Merge branch 'main' into feature/2d-astro-pi-model
G3zz Nov 5, 2026
ed94595
Update src/components/AstroPiModel/Simulator2d.jsx
G3zz Nov 5, 2026
6b61c6e
fix: copy quantised value back to Sk buffer
G3zz Nov 5, 2026
5615ec3
(via G3zz): fix: keep LED orientation when switching from 3D to 2D af…
macroscopeapp[bot] Nov 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 21 additions & 12 deletions COPYRIGHT
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,6 @@ Source: https://github.com/RaspberryPiFoundation/editor-ui
Files: *
Copyright: 2021-2025 Raspberry Pi Foundation <web@raspberrypi.org>
License: Apache-2.0
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
.
http://www.apache.org/licenses/LICENSE-2.0
.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.


Files: apps/scratch-frame
Copyright: 2025 Raspberry Pi Foundation <web@raspberrypi.org>
Expand All @@ -29,6 +17,27 @@ Files: public/pygal.js
Copyright: 2014 bzwheeler, trinket.io and other contributors <https://github.com/trinketapp/pygal.js>
License: MIT

Files: src/assets/icons/material_symbols/*
Copyright: Google LLC
License: Apache-2.0
Comment:
Icons obtained from Google Material Symbols:
- Font library: <https://fonts.google.com/icons>
- Upstream source: https://github.com/google/material-design-icons

License: Apache-2.0
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
.
http://www.apache.org/licenses/LICENSE-2.0
.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

License: AGPL-3.0
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
.
Expand Down
13 changes: 12 additions & 1 deletion cypress/e2e/missionZero-wc.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ it("defaults to the visual output tab", () => {
);
});

it("renders the astro pi component on page load", () => {
it("renders the 3D astro pi component on page load", () => {
getSkulptRunner().should("contain", "yaw");
});

Expand All @@ -42,6 +42,17 @@ it("loads the sense hat library", () => {
getResults().should("contain", '"isErrorFree":true');
});

it("switches between 3D and 2D visuals", () => {
getSkulptRunner().should("contain", "yaw");
getSkulptRunner()
.findByRole("button", { name: "Zoom in to 2D view" })
.click();
getSkulptRunner().should("not.contain", "yaw");
getSkulptRunner()
.findByRole("button", { name: "Zoom out to 3D view" })
.click();
});

it("sets initial criteria correctly", () => {
runCode("");

Expand Down
4 changes: 2 additions & 2 deletions cypress/e2e/spec-wc-skulpt.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,10 @@ describe("Running the code with skulpt", () => {
});

it("does not render astro pi component on page load", () => {
getSkulptRunner().should("not.contain", "yaw");
getSkulptRunner().should("not.contain", "Zoom in to 2D view");
});

it("renders astro pi component if sense hat imported", () => {
it("renders 3D astro pi component if sense hat imported", () => {
runCode("import sense_hat");

getSkulptTabByName("Visual output").click();
Expand Down
6 changes: 6 additions & 0 deletions public/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,12 @@
"newTab": "Preview in new tab",
"preview": "preview",
"senseHat": {
"view": {
"toggleTo2D": "Zoom in to 2D view",
"toggleTo3D": "Zoom out to 3D view",
"resetOrientation": "Reset Astro Pi orientation",
"description": "2D zoomed view of the Astro Pi 8 by 8 Sense HAT LED matrix"
},
"controls": {
"colour": "colour",
"humidity": "humidity",
Expand Down
1 change: 1 addition & 0 deletions src/assets/icons/material_symbols/zoom_in.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/icons/material_symbols/zoom_out.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
63 changes: 62 additions & 1 deletion src/assets/stylesheets/AstroPiModel.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
flex-flow: column;

&-model {
position: relative;
display: flex;
flex-flow: column;
max-block-size: 50%;
Expand Down Expand Up @@ -43,7 +44,6 @@
}

&__reset-btn {
flex: 1;
display: flex;
margin-inline-start: auto;
svg {
Expand All @@ -56,6 +56,67 @@
}
}
}
&-view-controls {
position: absolute;
inset-inline: 0;
display: flex;
flex-direction: row-reverse;
padding-block-start: 0.5rem;
margin: 0 var(--space-1);

button {
background-color: var(--rpf-white);
inline-size: 2rem;
block-size: 2rem;
border-radius: 0.25rem;
border: 1px solid var(--rpf-white);
font-family: var(--editor-font-family-sans-serif);
font-weight: 500;
display: flex;
justify-content: center;
align-items: center;
}
}
&-2d {
display: flex;
justify-content: center;
padding-block-start: var(--space-0-5);
flex: 1;
}
&-2d-matrix {
padding: 1%;
display: grid;
background-color: darkgrey;
grid-template-columns: repeat(8, 1fr);
grid-template-rows: repeat(8, 1fr);
gap: 1%;
aspect-ratio: 1 / 1;
max-block-size: 100%;
max-inline-size: 100%;

&__led-housing {
display: flex;
background-color: #c9cacd;
border-width: 2px 2px 2px 1px;
border-style: solid;
justify-content: center;
align-items: center;
border-block-start-color: #cfcfcf;
border-inline-start-color: lightgrey;
border-block-end-color: #cfcfcf;
border-inline-end-color: grey;
}
&__led-bulb {
box-sizing: border-box;
block-size: 90%;
inline-size: 90%;
// controls the led circle
border-width: 0.5px;
border-style: solid;
border-color: grey;
border-radius: 25%;
}
}
}

&-controls {
Expand Down
46 changes: 36 additions & 10 deletions src/components/AstroPiModel/AstroPiModel.jsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,36 @@
import React from "react";
import "../../assets/stylesheets/AstroPiModel.scss?inline";
import Simulator from "./Simulator";
import Simulator2d from "./Simulator2d";
import Sk from "skulpt";
import AstroPiControls from "./AstroPiControls/AstroPiControls";
import OrientationPanel from "./OrientationPanel/OrientationPanel";
import ViewModeControls from "./ViewModeControls";
import { useEffect, useState } from "react";
import { resetModel, updateRTIMU } from "../../utils/Orientation";
import { useSelector } from "react-redux";
import { defaultMZCriteria } from "../../utils/DefaultMZCriteria";
import { rotate, rotationClockwise90degrees } from "../../utils/senseHatUtils";

const AstroPiModel = () => {
const B = [207, 207, 207];
const W = [235, 235, 235];
const SMILEY_FACE = rotate(
rotationClockwise90degrees,
// prettier-ignore
[
B, B, B, B, B, B, B, W,
B, B, B, B, B, B, B, B,
W, W, W, B, B, W, W, W,
W, B, W, B, B, W, B, W,
W, W, W, B, B, W, W, W,
B, B, B, B, B, B, B, B,
B, B, W, B, B, W, B, B,
B, B, W, W, W, W, B, B
],
);

const AstroPiModel = ({ initialIs3d = true }) => {
const project = useSelector((state) => state.editor.project);
const [is3d, setIs3d] = useState(initialIs3d);
const [orientation, setOrientation] = useState([0, 90, 0]);
const resetOrientation = (e) => {
resetModel(e);
Expand Down Expand Up @@ -58,9 +78,7 @@ const AstroPiModel = () => {
start_motion_callback: () => {},
stop_motion_callback: () => {},
};
for (var i = 0; i < 64; i++) {
Sk.sense_hat.pixels.push([0, 0, 0]);
}
Sk.sense_hat.pixels = SMILEY_FACE;
}

useEffect(() => {
Expand All @@ -75,11 +93,19 @@ const AstroPiModel = () => {
return (
<div className="sense-hat">
<div className="sense-hat-model">
<Simulator updateOrientation={setOrientation} />
<OrientationPanel
orientation={orientation}
resetOrientation={resetOrientation}
/>
<>
{is3d && (
<>
<Simulator updateOrientation={setOrientation} />
<OrientationPanel
orientation={orientation}
resetOrientation={resetOrientation}
/>
</>
)}
<ViewModeControls is3d={is3d} setIs3d={setIs3d} />
{!is3d && <Simulator2d />}
</>
</div>

{/* <!-- Full sensor controls --> */}
Expand Down
Loading
Loading